* fixed null terminated string handling
[kai/samba-autobuild/.git] / source4 / librpc / rpc / dcerpc.c
1 /* 
2    Unix SMB/CIFS implementation.
3    raw dcerpc operations
4
5    Copyright (C) Tim Potter 2003
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /* initialise a dcerpc pipe. This currently assumes a SMB named pipe
26    transport */
27 struct dcerpc_pipe *dcerpc_pipe_init(struct cli_tree *tree)
28 {
29         struct dcerpc_pipe *p;
30
31         TALLOC_CTX *mem_ctx = talloc_init("dcerpc_tree");
32         if (mem_ctx == NULL)
33                 return NULL;
34
35         p = talloc(mem_ctx, sizeof(*p));
36         if (!p) {
37                 talloc_destroy(mem_ctx);
38                 return NULL;
39         }
40
41         p->reference_count = 0;
42         p->mem_ctx = mem_ctx;
43         p->tree = tree;
44         p->tree->reference_count++;
45         p->call_id = 1;
46         p->fnum = 0;
47
48         return p;
49 }
50
51 /* close down a dcerpc over SMB pipe */
52 void dcerpc_pipe_close(struct dcerpc_pipe *p)
53 {
54         if (!p) return;
55         p->reference_count--;
56         if (p->reference_count <= 0) {
57                 cli_tree_close(p->tree);
58                 talloc_destroy(p->mem_ctx);
59         }
60 }
61
62 #define BLOB_CHECK_BOUNDS(blob, offset, len) do { \
63         if ((offset) > blob->length || (blob->length - (offset) < (len))) { \
64                 return NT_STATUS_INVALID_PARAMETER; \
65         } \
66 } while (0)
67
68 #define DCERPC_ALIGN(offset, n) do { \
69         (offset) = ((offset) + ((n)-1)) & ~((n)-1); \
70 } while (0)
71
72 /*
73   pull a wire format uuid into a string. This will consume 16 bytes
74 */
75 static char *dcerpc_pull_uuid(char *data, TALLOC_CTX *mem_ctx)
76 {
77         uint32 time_low;
78         uint16 time_mid, time_hi_and_version;
79         uint8 clock_seq_hi_and_reserved;
80         uint8 clock_seq_low;
81         uint8 node[6];
82         int i;
83
84         time_low                  = IVAL(data, 0);
85         time_mid                  = SVAL(data, 4);
86         time_hi_and_version       = SVAL(data, 6);
87         clock_seq_hi_and_reserved = CVAL(data, 8);
88         clock_seq_low             = CVAL(data, 9);
89         for (i=0;i<6;i++) {
90                 node[i]           = CVAL(data, 10 + i);
91         }
92
93         return talloc_asprintf(mem_ctx, 
94                                "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
95                                time_low, time_mid, time_hi_and_version, 
96                                clock_seq_hi_and_reserved, clock_seq_low,
97                                node[0], node[1], node[2], node[3], node[4], node[5]);
98 }
99
100 /*
101   push a uuid_str into wire format. It will consume 16 bytes
102 */
103 static NTSTATUS push_uuid_str(char *data, const char *uuid_str)
104 {
105         uint32 time_low;
106         uint32 time_mid, time_hi_and_version;
107         uint32 clock_seq_hi_and_reserved;
108         uint32 clock_seq_low;
109         uint32 node[6];
110         int i;
111
112         if (11 != sscanf(uuid_str, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
113                          &time_low, &time_mid, &time_hi_and_version, 
114                          &clock_seq_hi_and_reserved, &clock_seq_low,
115                          &node[0], &node[1], &node[2], &node[3], &node[4], &node[5])) {
116                 return NT_STATUS_INVALID_PARAMETER;
117         }
118
119         SIVAL(data, 0, time_low);
120         SSVAL(data, 4, time_mid);
121         SSVAL(data, 6, time_hi_and_version);
122         SCVAL(data, 8, clock_seq_hi_and_reserved);
123         SCVAL(data, 9, clock_seq_low);
124         for (i=0;i<6;i++) {
125                 SCVAL(data, 10 + i, node[i]);
126         }
127
128         return NT_STATUS_OK;
129 }
130
131 /*
132   pull a dcerpc syntax id from a blob
133 */
134 static NTSTATUS dcerpc_pull_syntax_id(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
135                                       uint32 *offset, 
136                                       struct dcerpc_syntax_id *syntax)
137 {
138         syntax->uuid_str = dcerpc_pull_uuid(blob->data + (*offset), mem_ctx);
139         if (!syntax->uuid_str) {
140                 return NT_STATUS_NO_MEMORY;
141         }
142         (*offset) += 16;
143         syntax->if_version = IVAL(blob->data, *offset);
144         (*offset) += 4;
145         return NT_STATUS_OK;
146 }
147
148 /*
149   push a syntax id onto the wire. It will consume 20 bytes
150 */
151 static NTSTATUS push_syntax_id(char *data, const struct dcerpc_syntax_id *syntax)
152 {
153         NTSTATUS status;
154
155         status = push_uuid_str(data, syntax->uuid_str);
156         SIVAL(data, 16, syntax->if_version);
157
158         return status;
159 }
160
161 /*
162   pull an auth verifier from a packet
163 */
164 static NTSTATUS dcerpc_pull_auth_verifier(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
165                                           uint32 *offset, 
166                                           struct dcerpc_hdr *hdr,
167                                           DATA_BLOB *auth)
168 {
169         if (hdr->auth_length == 0) {
170                 return NT_STATUS_OK;
171         }
172
173         BLOB_CHECK_BOUNDS(blob, *offset, hdr->auth_length);
174         *auth = data_blob_talloc(mem_ctx, blob->data + (*offset), hdr->auth_length);
175         if (!auth->data) {
176                 return NT_STATUS_NO_MEMORY;
177         }
178         (*offset) += hdr->auth_length;
179         return NT_STATUS_OK;
180 }
181
182 /* 
183    parse a struct dcerpc_response
184 */
185 static NTSTATUS dcerpc_pull_response(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
186                                      uint32 *offset, 
187                                      struct dcerpc_hdr *hdr,
188                                      struct dcerpc_response *pkt)
189 {
190         uint32 stub_len;
191         
192         BLOB_CHECK_BOUNDS(blob, *offset, 8);
193
194         pkt->alloc_hint   = IVAL(blob->data, (*offset) + 0);
195         pkt->context_id   = SVAL(blob->data, (*offset) + 4);
196         pkt->cancel_count = CVAL(blob->data, (*offset) + 6);
197
198         (*offset) += 8;
199
200         stub_len = blob->length - ((*offset) + hdr->auth_length);
201         BLOB_CHECK_BOUNDS(blob, *offset, stub_len);
202         pkt->stub_data = data_blob_talloc(mem_ctx, blob->data + (*offset), stub_len);
203         if (stub_len != 0 && !pkt->stub_data.data) {
204                 return NT_STATUS_NO_MEMORY;
205         }
206         (*offset) += stub_len;
207
208         return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);      
209 }
210
211
212 /* 
213    parse a struct bind_ack
214 */
215 static NTSTATUS dcerpc_pull_bind_ack(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
216                                      uint32 *offset, 
217                                      struct dcerpc_hdr *hdr,
218                                      struct dcerpc_bind_ack *pkt)
219 {
220         uint16 len;
221         int i;
222         
223         BLOB_CHECK_BOUNDS(blob, *offset, 10);
224         pkt->max_xmit_frag  = SVAL(blob->data, (*offset) + 0);
225         pkt->max_recv_frag  = SVAL(blob->data, (*offset) + 2);
226         pkt->assoc_group_id = IVAL(blob->data, (*offset) + 4);
227         len                 = SVAL(blob->data, (*offset) + 8);
228         (*offset) += 10;
229
230         if (len) {
231                 BLOB_CHECK_BOUNDS(blob, *offset, len);
232                 pkt->secondary_address = talloc_strndup(mem_ctx, blob->data + (*offset), len);
233                 if (!pkt->secondary_address) {
234                         return NT_STATUS_NO_MEMORY;
235                 }
236                 (*offset) += len;
237         }
238
239         DCERPC_ALIGN(*offset, 4);
240         BLOB_CHECK_BOUNDS(blob, *offset, 4);
241         pkt->num_results = CVAL(blob->data, *offset); 
242         (*offset) += 4;
243
244         if (pkt->num_results > 0) {
245                 pkt->ctx_list = talloc(mem_ctx, sizeof(pkt->ctx_list[0]) * pkt->num_results);
246                 if (!pkt->ctx_list) {
247                         return NT_STATUS_NO_MEMORY;
248                 }
249         }
250
251         for (i=0;i<pkt->num_results;i++) {
252                 NTSTATUS status;
253
254                 BLOB_CHECK_BOUNDS(blob, *offset, 24);
255                 pkt->ctx_list[i].result = SVAL(blob->data, *offset);
256                 pkt->ctx_list[i].reason = SVAL(blob->data, 2 + *offset);
257                 (*offset) += 4;
258                 status = dcerpc_pull_syntax_id(blob, mem_ctx, offset, &pkt->ctx_list[i].syntax);
259                 if (!NT_STATUS_IS_OK(status)) {
260                         return status;
261                 }
262         }
263
264         return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
265 }
266
267
268 /* 
269    parse a dcerpc header
270 */
271 static NTSTATUS dcerpc_pull_hdr(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr)
272 {
273         BLOB_CHECK_BOUNDS(blob, *offset, 16);
274         
275         hdr->rpc_vers       = CVAL(blob->data, (*offset) + 0);
276         hdr->rpc_vers_minor = CVAL(blob->data, (*offset) + 1);
277         hdr->ptype          = CVAL(blob->data, (*offset) + 2);
278         hdr->pfc_flags      = CVAL(blob->data, (*offset) + 3);
279         memcpy(hdr->drep, blob->data + (*offset) + 4, 4);
280         hdr->frag_length    = SVAL(blob->data, (*offset) + 8);
281         hdr->auth_length    = SVAL(blob->data, (*offset) + 10);
282         hdr->call_id        = IVAL(blob->data, (*offset) + 12);
283
284         (*offset) += 16;
285
286         return NT_STATUS_OK;
287 }
288
289 /* 
290    parse a dcerpc header. It consumes 16 bytes
291 */
292 static void dcerpc_push_hdr(char *data, struct dcerpc_hdr *hdr)
293 {
294         SCVAL(data, 0, hdr->rpc_vers);
295         SCVAL(data, 1, hdr->rpc_vers_minor);
296         SCVAL(data, 2, hdr->ptype);
297         SCVAL(data, 3, hdr->pfc_flags);
298         memcpy(data + 4, hdr->drep, 4);
299         SSVAL(data, 8, hdr->frag_length);
300         SSVAL(data, 12, hdr->call_id);
301 }
302
303
304
305 /* 
306    parse a data blob into a dcerpc_packet structure. This handles both
307    input and output packets
308 */
309 NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
310 {
311         NTSTATUS status;
312         uint32 offset = 0;
313
314         status = dcerpc_pull_hdr(blob, &offset, &pkt->hdr);
315         if (!NT_STATUS_IS_OK(status)) {
316                 return status;
317         }
318
319         switch (pkt->hdr.ptype) {
320         case DCERPC_PKT_BIND_ACK:
321                 status = dcerpc_pull_bind_ack(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.bind_ack);
322                 if (!NT_STATUS_IS_OK(status)) {
323                         return status;
324                 }               
325                 break;
326
327         case DCERPC_PKT_RESPONSE:
328                 status = dcerpc_pull_response(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.response);
329                 if (!NT_STATUS_IS_OK(status)) {
330                         return status;
331                 }               
332                 break;
333
334         default:
335                 return NT_STATUS_NET_WRITE_FAULT;
336         }
337
338         return status;
339 }
340
341
342 /* 
343    push a dcerpc_bind into a blob
344 */
345 static NTSTATUS dcerpc_push_bind(DATA_BLOB *blob, uint32 *offset,
346                                  struct dcerpc_hdr *hdr,
347                                  struct dcerpc_bind *pkt)
348 {
349         int i, j;
350
351         SSVAL(blob->data, (*offset) + 0, pkt->max_xmit_frag);
352         SSVAL(blob->data, (*offset) + 2, pkt->max_recv_frag);
353         SIVAL(blob->data, (*offset) + 4, pkt->assoc_group_id);
354         SCVAL(blob->data, (*offset) + 8, pkt->num_contexts);
355         (*offset) += 12;
356
357         for (i=0;i<pkt->num_contexts;i++) {
358                 NTSTATUS status;
359
360                 SSVAL(blob->data, (*offset) + 0, pkt->ctx_list[i].context_id);
361                 SCVAL(blob->data, (*offset) + 2, pkt->ctx_list[i].num_transfer_syntaxes);
362                 status = push_syntax_id(blob->data + (*offset) + 4, &pkt->ctx_list[i].abstract_syntax);
363                 if (!NT_STATUS_IS_OK(status)) {
364                         return status;
365                 }
366                 (*offset) += 24;
367                 for (j=0;j<pkt->ctx_list[i].num_transfer_syntaxes;j++) {
368                         status = push_syntax_id(blob->data + (*offset), 
369                                                 &pkt->ctx_list[i].transfer_syntaxes[j]);
370                         if (!NT_STATUS_IS_OK(status)) {
371                                 return status;
372                         }
373                         (*offset) += 20;
374                 }
375         }
376
377         return NT_STATUS_OK;
378 }
379
380 /* 
381    push a dcerpc_request into a blob
382 */
383 static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset,
384                                     struct dcerpc_hdr *hdr,
385                                     struct dcerpc_request *pkt)
386 {
387         SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint);
388         SSVAL(blob->data, (*offset) + 4, pkt->context_id);
389         SSVAL(blob->data, (*offset) + 6, pkt->opnum);
390
391         (*offset) += 8;
392
393         memcpy(blob->data + (*offset), pkt->stub_data.data, pkt->stub_data.length);
394         (*offset) += pkt->stub_data.length;
395
396         memcpy(blob->data + (*offset), pkt->auth_verifier.data, pkt->auth_verifier.length);
397         (*offset) += pkt->auth_verifier.length;
398
399         return NT_STATUS_OK;
400 }
401
402
403 /*
404   work out the wire size of a dcerpc packet 
405 */
406 static uint32 dcerpc_wire_size(struct dcerpc_packet *pkt)
407 {
408         int i;
409         uint32 size = 0;
410
411         size += 16; /* header */
412
413         switch (pkt->hdr.ptype) {
414         case DCERPC_PKT_REQUEST:
415                 size += 8;
416                 size += pkt->in.request.stub_data.length;
417                 size += pkt->in.request.auth_verifier.length;
418                 break;
419
420         case DCERPC_PKT_RESPONSE:
421                 size += 8;
422                 size += pkt->out.response.stub_data.length;
423                 size += pkt->hdr.auth_length;
424                 break;
425
426         case DCERPC_PKT_BIND:
427                 size += 12;
428                 for (i=0;i<pkt->in.bind.num_contexts;i++) {
429                         size += 24;
430                         size += pkt->in.bind.ctx_list[i].num_transfer_syntaxes * 20;
431                 }
432                 size += pkt->hdr.auth_length;
433                 break;
434
435         case DCERPC_PKT_BIND_ACK:
436                 size += 10;
437                 if (pkt->out.bind_ack.secondary_address) {
438                         size += strlen(pkt->out.bind_ack.secondary_address) + 1;
439                 }
440                 size += 4;
441                 size += pkt->out.bind_ack.num_results * 24;
442                 size += pkt->hdr.auth_length;
443                 break;
444         }
445
446         return size;
447 }
448
449 /* 
450    push a dcerpc_packet into a blob. This handles both input and
451    output packets
452 */
453 NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
454 {
455         uint32 offset = 0;
456         uint32 wire_size;
457         NTSTATUS status;
458
459         /* work out how big the packet will be on the wire */
460         wire_size = dcerpc_wire_size(pkt);
461
462         (*blob) = data_blob_talloc(mem_ctx, NULL, wire_size);
463         if (!blob->data) {
464                 return NT_STATUS_NO_MEMORY;
465         }
466
467         pkt->hdr.frag_length = wire_size;
468
469         dcerpc_push_hdr(blob->data + offset, &pkt->hdr);
470         offset += 16;
471
472         switch (pkt->hdr.ptype) {
473         case DCERPC_PKT_BIND:
474                 status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind);
475                 break;
476
477         case DCERPC_PKT_REQUEST:
478                 status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request);
479                 break;
480                 
481         default:
482                 status = NT_STATUS_NET_WRITE_FAULT;
483         }
484
485         return status;
486 }
487
488
489
490
491 /* 
492    fill in the fixed values in a dcerpc header 
493 */
494 static void init_dcerpc_hdr(struct dcerpc_hdr *hdr)
495 {
496         hdr->rpc_vers = 5;
497         hdr->rpc_vers_minor = 0;
498         hdr->drep[0] = 0x10; /* Little endian */
499         hdr->drep[1] = 0;
500         hdr->drep[2] = 0;
501         hdr->drep[3] = 0;
502 }
503
504
505 /* 
506    perform a bind using the given syntax 
507 */
508 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
509                      const struct dcerpc_syntax_id *syntax,
510                      const struct dcerpc_syntax_id *transfer_syntax)
511 {
512         TALLOC_CTX *mem_ctx;
513         struct dcerpc_packet pkt;
514         NTSTATUS status;
515         DATA_BLOB blob;
516         DATA_BLOB blob_out;
517
518         mem_ctx = talloc_init("dcerpc_bind");
519         if (!mem_ctx) {
520                 return NT_STATUS_NO_MEMORY;
521         }
522
523         init_dcerpc_hdr(&pkt.hdr);
524
525         pkt.hdr.ptype = DCERPC_PKT_BIND;
526         pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
527         pkt.hdr.call_id = p->call_id++;
528         pkt.hdr.auth_length = 0;
529
530         pkt.in.bind.max_xmit_frag = 0x2000;
531         pkt.in.bind.max_recv_frag = 0x2000;
532         pkt.in.bind.assoc_group_id = 0;
533         pkt.in.bind.num_contexts = 1;
534         pkt.in.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.in.bind.ctx_list[0]));
535         if (!pkt.in.bind.ctx_list) {
536                 talloc_destroy(mem_ctx);
537                 return NT_STATUS_NO_MEMORY;
538         }
539         pkt.in.bind.ctx_list[0].context_id = 0;
540         pkt.in.bind.ctx_list[0].num_transfer_syntaxes = 1;
541         pkt.in.bind.ctx_list[0].abstract_syntax = *syntax;
542         pkt.in.bind.ctx_list[0].transfer_syntaxes = transfer_syntax;
543
544         pkt.in.bind.auth_verifier = data_blob(NULL, 0);
545
546         status = dcerpc_push(&blob, mem_ctx, &pkt);
547         if (!NT_STATUS_IS_OK(status)) {
548                 talloc_destroy(mem_ctx);
549                 return status;
550         }
551
552         status = dcerpc_raw_packet(p, mem_ctx, &blob, &blob_out);
553         if (!NT_STATUS_IS_OK(status)) {
554                 talloc_destroy(mem_ctx);
555                 return status;
556         }
557
558         status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
559         if (!NT_STATUS_IS_OK(status)) {
560                 talloc_destroy(mem_ctx);
561                 return status;
562         }
563
564         if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK ||
565             pkt.out.bind_ack.num_results == 0 ||
566             pkt.out.bind_ack.ctx_list[0].result != 0) {
567                 status = NT_STATUS_UNSUCCESSFUL;
568         }
569
570         p->srv_max_xmit_frag = pkt.out.bind_ack.max_xmit_frag;
571         p->srv_max_recv_frag = pkt.out.bind_ack.max_recv_frag;
572
573         talloc_destroy(mem_ctx);
574
575         return status;  
576 }
577
578 /* Perform a bind using the given UUID and version */
579 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
580                             const char *uuid, unsigned version)
581 {
582         struct dcerpc_syntax_id syntax;
583         struct dcerpc_syntax_id transfer_syntax;
584
585         syntax.uuid_str = uuid;
586         syntax.if_version = version;
587
588         transfer_syntax.uuid_str = "8a885d04-1ceb-11c9-9fe8-08002b104860";
589         transfer_syntax.if_version = 2;
590
591         return dcerpc_bind(p, &syntax, &transfer_syntax);
592 }
593
594 /*
595   perform a full request/response pair on a dcerpc pipe
596 */
597 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
598                         uint16 opnum,
599                         TALLOC_CTX *mem_ctx,
600                         DATA_BLOB *stub_data_in,
601                         DATA_BLOB *stub_data_out)
602 {
603         
604         struct dcerpc_packet pkt;
605         NTSTATUS status;
606         DATA_BLOB blob_in, blob_out, payload;
607         uint32 remaining, chunk_size;
608
609         init_dcerpc_hdr(&pkt.hdr);
610
611         remaining = stub_data_in->length;
612
613         /* we can write a full max_recv_frag size, minus the dcerpc
614            request header size */
615         chunk_size = p->srv_max_recv_frag - 24;
616
617         pkt.hdr.ptype = DCERPC_PKT_REQUEST;
618         pkt.hdr.call_id = p->call_id++;
619         pkt.hdr.auth_length = 0;
620         pkt.in.request.alloc_hint = remaining;
621         pkt.in.request.context_id = 0;
622         pkt.in.request.opnum = opnum;
623         pkt.in.request.auth_verifier = data_blob(NULL, 0);
624
625         /* we send a series of pdus without waiting for a reply until
626            the last pdu */
627         while (remaining > chunk_size) {
628                 if (remaining == stub_data_in->length) {
629                         pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST;
630                 } else {
631                         pkt.hdr.pfc_flags = 0;
632                 }
633
634                 pkt.in.request.stub_data.data = stub_data_in->data + 
635                         (stub_data_in->length - remaining);
636                 pkt.in.request.stub_data.length = chunk_size;
637
638                 status = dcerpc_push(&blob_in, mem_ctx, &pkt);
639                 if (!NT_STATUS_IS_OK(status)) {
640                         return status;
641                 }
642                 
643                 status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in);
644                 if (!NT_STATUS_IS_OK(status)) {
645                         return status;
646                 }               
647
648                 remaining -= chunk_size;
649         }
650
651         /* now we send a pdu with LAST_FRAG sent and get the first
652            part of the reply */
653         if (remaining == stub_data_in->length) {
654                 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
655         } else {
656                 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST;
657         }
658         pkt.in.request.stub_data.data = stub_data_in->data + 
659                 (stub_data_in->length - remaining);
660         pkt.in.request.stub_data.length = remaining;
661         
662         status = dcerpc_push(&blob_in, mem_ctx, &pkt);
663         if (!NT_STATUS_IS_OK(status)) {
664                 return status;
665         }
666
667         /* send the pdu and get the initial response pdu */
668         status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out);
669
670         status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
671         if (!NT_STATUS_IS_OK(status)) {
672                 return status;
673         }
674
675         if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
676                 return NT_STATUS_UNSUCCESSFUL;
677         }
678
679         if (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
680                 /* something is badly wrong! */
681                 return NT_STATUS_UNSUCCESSFUL;
682         }
683
684         payload = pkt.out.response.stub_data;
685
686         /* continue receiving fragments */
687         while (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
688                 uint32 length;
689
690                 status = dcerpc_raw_packet_secondary(p, mem_ctx, &blob_out);
691                 if (!NT_STATUS_IS_OK(status)) {
692                         return status;
693                 }
694
695                 status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
696                 if (!NT_STATUS_IS_OK(status)) {
697                         return status;
698                 }
699
700                 if (pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
701                         /* start of another packet!? */
702                         return NT_STATUS_UNSUCCESSFUL;
703                 }
704
705                 if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
706                         return NT_STATUS_UNSUCCESSFUL;
707                 }
708
709                 length = pkt.out.response.stub_data.length;
710
711                 payload.data = talloc_realloc(mem_ctx, 
712                                               payload.data, 
713                                               payload.length + length);
714                 if (!payload.data) {
715                         return NT_STATUS_NO_MEMORY;
716                 }
717
718                 memcpy(payload.data + payload.length,
719                        pkt.out.response.stub_data.data,
720                        length);
721
722                 payload.length += length;
723         }
724
725         if (stub_data_out) {
726                 *stub_data_out = payload;
727         }
728
729         return status;
730 }
731
732
733 /*
734   this is a paranoid NDR validator. For every packet we push onto the wire
735   we pull it back again, then push it again. Then we compare the raw NDR data
736   for that to the NDR we initially generated. If they don't match then we know
737   we must have a bug in either the pull or push side of our code
738 */
739 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
740                                        DATA_BLOB blob,
741                                        size_t struct_size,
742                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
743                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
744 {
745         void *st;
746         struct ndr_pull *pull;
747         struct ndr_push *push;
748         NTSTATUS status;
749         DATA_BLOB blob2;
750
751         st = talloc(mem_ctx, struct_size);
752         if (!st) {
753                 return NT_STATUS_NO_MEMORY;
754         }
755
756         pull = ndr_pull_init_blob(&blob, mem_ctx);
757         if (!pull) {
758                 return NT_STATUS_NO_MEMORY;
759         }
760
761         status = ndr_pull(pull, NDR_IN, st);
762         if (!NT_STATUS_IS_OK(status)) {
763                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
764                                       "failed input validation pull - %s",
765                                       nt_errstr(status));
766         }
767
768         push = ndr_push_init_ctx(mem_ctx);
769         if (!push) {
770                 return NT_STATUS_NO_MEMORY;
771         }       
772
773         status = ndr_push(push, NDR_IN, st);
774         if (!NT_STATUS_IS_OK(status)) {
775                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
776                                       "failed input validation push - %s",
777                                       nt_errstr(status));
778         }
779
780         blob2 = ndr_push_blob(push);
781
782         if (!data_blob_equal(&blob, &blob2)) {
783                 DEBUG(3,("original:\n"));
784                 dump_data(3, blob.data, blob.length);
785                 DEBUG(3,("secondary:\n"));
786                 dump_data(3, blob2.data, blob2.length);
787                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
788                                       "failed input validation data - %s",
789                                       nt_errstr(status));
790         }
791
792         return NT_STATUS_OK;
793 }
794
795 /*
796   this is a paranoid NDR input validator. For every packet we pull
797   from the wire we push it back again then pull and push it
798   again. Then we compare the raw NDR data for that to the NDR we
799   initially generated. If they don't match then we know we must have a
800   bug in either the pull or push side of our code
801 */
802 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
803                                         void *struct_ptr,
804                                         size_t struct_size,
805                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
806                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
807 {
808         void *st;
809         struct ndr_pull *pull;
810         struct ndr_push *push;
811         NTSTATUS status;
812         DATA_BLOB blob, blob2;
813
814         st = talloc(mem_ctx, struct_size);
815         if (!st) {
816                 return NT_STATUS_NO_MEMORY;
817         }
818         memcpy(st, struct_ptr, struct_size);
819
820         push = ndr_push_init_ctx(mem_ctx);
821         if (!push) {
822                 return NT_STATUS_NO_MEMORY;
823         }       
824
825         status = ndr_push(push, NDR_OUT, struct_ptr);
826         if (!NT_STATUS_IS_OK(status)) {
827                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
828                                       "failed output validation push - %s",
829                                       nt_errstr(status));
830         }
831
832         blob = ndr_push_blob(push);
833
834         pull = ndr_pull_init_blob(&blob, mem_ctx);
835         if (!pull) {
836                 return NT_STATUS_NO_MEMORY;
837         }
838
839         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
840         status = ndr_pull(pull, NDR_OUT, st);
841         if (!NT_STATUS_IS_OK(status)) {
842                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
843                                       "failed output validation pull - %s",
844                                       nt_errstr(status));
845         }
846
847         push = ndr_push_init_ctx(mem_ctx);
848         if (!push) {
849                 return NT_STATUS_NO_MEMORY;
850         }       
851
852         status = ndr_push(push, NDR_OUT, st);
853         if (!NT_STATUS_IS_OK(status)) {
854                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
855                                       "failed output validation push2 - %s",
856                                       nt_errstr(status));
857         }
858
859         blob2 = ndr_push_blob(push);
860
861         if (!data_blob_equal(&blob, &blob2)) {
862                 DEBUG(3,("original:\n"));
863                 dump_data(3, blob.data, blob.length);
864                 DEBUG(3,("secondary:\n"));
865                 dump_data(3, blob2.data, blob2.length);
866                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
867                                       "failed output validation data - %s",
868                                       nt_errstr(status));
869         }
870
871         return NT_STATUS_OK;
872 }
873
874 /*
875   a useful helper function for synchronous rpc requests 
876
877   this can be used when you have ndr push/pull functions in the
878   standard format
879 */
880 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
881                             uint32 opnum,
882                             TALLOC_CTX *mem_ctx,
883                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
884                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
885                             void *struct_ptr,
886                             size_t struct_size)
887 {
888         struct ndr_push *push;
889         struct ndr_pull *pull;
890         NTSTATUS status;
891         DATA_BLOB request, response;
892
893         /* setup for a ndr_push_* call */
894         push = ndr_push_init();
895         if (!push) {
896                 talloc_destroy(mem_ctx);
897                 return NT_STATUS_NO_MEMORY;
898         }
899
900         /* push the structure into a blob */
901         status = ndr_push(push, NDR_IN, struct_ptr);
902         if (!NT_STATUS_IS_OK(status)) {
903                 goto failed;
904         }
905
906         /* retrieve the blob */
907         request = ndr_push_blob(push);
908
909         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
910                 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size, 
911                                                 ndr_push, ndr_pull);
912                 if (!NT_STATUS_IS_OK(status)) {
913                         goto failed;
914                 }
915         }
916
917         DEBUG(10,("rpc request data:\n"));
918         dump_data(10, request.data, request.length);
919
920         /* make the actual dcerpc request */
921         status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
922         if (!NT_STATUS_IS_OK(status)) {
923                 goto failed;
924         }
925
926         /* prepare for ndr_pull_* */
927         pull = ndr_pull_init_blob(&response, mem_ctx);
928         if (!pull) {
929                 goto failed;
930         }
931
932         DEBUG(10,("rpc reply data:\n"));
933         dump_data(10, pull->data, pull->data_size);
934
935         /* pull the structure from the blob */
936         status = ndr_pull(pull, NDR_OUT, struct_ptr);
937         if (!NT_STATUS_IS_OK(status)) {
938                 goto failed;
939         }
940
941         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
942                 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size, 
943                                                  ndr_push, ndr_pull);
944                 if (!NT_STATUS_IS_OK(status)) {
945                         goto failed;
946                 }
947         }
948
949         if (pull->offset != pull->data_size) {
950                 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
951                 status = NT_STATUS_INFO_LENGTH_MISMATCH;
952                 goto failed;
953         }
954
955 failed:
956         ndr_push_free(push);
957         return status;
958 }
959
960
961 /*
962   a useful function for retrieving the server name we connected to
963 */
964 const char *dcerpc_server_name(struct dcerpc_pipe *p)
965 {
966         return p->tree->session->transport->called.name;
967 }