use the auto-generated UUID, version and name rather than listing them
[ira/wip.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 = IVAL(blob->data, *offset);
256                 (*offset) += 4;
257                 status = dcerpc_pull_syntax_id(blob, mem_ctx, offset, &pkt->ctx_list[i].syntax);
258                 if (!NT_STATUS_IS_OK(status)) {
259                         return status;
260                 }
261         }
262
263         return dcerpc_pull_auth_verifier(blob, mem_ctx, offset, hdr, &pkt->auth_verifier);
264 }
265
266
267 /* 
268    parse a dcerpc header
269 */
270 static NTSTATUS dcerpc_pull_hdr(DATA_BLOB *blob, uint32 *offset, struct dcerpc_hdr *hdr)
271 {
272         BLOB_CHECK_BOUNDS(blob, *offset, 16);
273         
274         hdr->rpc_vers       = CVAL(blob->data, (*offset) + 0);
275         hdr->rpc_vers_minor = CVAL(blob->data, (*offset) + 1);
276         hdr->ptype          = CVAL(blob->data, (*offset) + 2);
277         hdr->pfc_flags      = CVAL(blob->data, (*offset) + 3);
278         memcpy(hdr->drep, blob->data + (*offset) + 4, 4);
279         hdr->frag_length    = SVAL(blob->data, (*offset) + 8);
280         hdr->auth_length    = SVAL(blob->data, (*offset) + 10);
281         hdr->call_id        = IVAL(blob->data, (*offset) + 12);
282
283         (*offset) += 16;
284
285         return NT_STATUS_OK;
286 }
287
288 /* 
289    parse a dcerpc header. It consumes 16 bytes
290 */
291 static void dcerpc_push_hdr(char *data, struct dcerpc_hdr *hdr)
292 {
293         SCVAL(data, 0, hdr->rpc_vers);
294         SCVAL(data, 1, hdr->rpc_vers_minor);
295         SCVAL(data, 2, hdr->ptype);
296         SCVAL(data, 3, hdr->pfc_flags);
297         memcpy(data + 4, hdr->drep, 4);
298         SSVAL(data, 8, hdr->frag_length);
299         SSVAL(data, 12, hdr->call_id);
300 }
301
302
303
304 /* 
305    parse a data blob into a dcerpc_packet structure. This handles both
306    input and output packets
307 */
308 NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
309 {
310         NTSTATUS status;
311         uint32 offset = 0;
312
313         status = dcerpc_pull_hdr(blob, &offset, &pkt->hdr);
314         if (!NT_STATUS_IS_OK(status)) {
315                 return status;
316         }
317
318         switch (pkt->hdr.ptype) {
319         case DCERPC_PKT_BIND_ACK:
320                 status = dcerpc_pull_bind_ack(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.bind_ack);
321                 if (!NT_STATUS_IS_OK(status)) {
322                         return status;
323                 }               
324                 break;
325
326         case DCERPC_PKT_RESPONSE:
327                 status = dcerpc_pull_response(blob, mem_ctx, &offset, &pkt->hdr, &pkt->out.response);
328                 if (!NT_STATUS_IS_OK(status)) {
329                         return status;
330                 }               
331                 break;
332
333         default:
334                 return NT_STATUS_NET_WRITE_FAULT;
335         }
336
337         return status;
338 }
339
340
341 /* 
342    push a dcerpc_bind into a blob
343 */
344 static NTSTATUS dcerpc_push_bind(DATA_BLOB *blob, uint32 *offset,
345                                  struct dcerpc_hdr *hdr,
346                                  struct dcerpc_bind *pkt)
347 {
348         int i, j;
349
350         SSVAL(blob->data, (*offset) + 0, pkt->max_xmit_frag);
351         SSVAL(blob->data, (*offset) + 2, pkt->max_recv_frag);
352         SIVAL(blob->data, (*offset) + 4, pkt->assoc_group_id);
353         SCVAL(blob->data, (*offset) + 8, pkt->num_contexts);
354         (*offset) += 12;
355
356         for (i=0;i<pkt->num_contexts;i++) {
357                 NTSTATUS status;
358
359                 SSVAL(blob->data, (*offset) + 0, pkt->ctx_list[i].context_id);
360                 SCVAL(blob->data, (*offset) + 2, pkt->ctx_list[i].num_transfer_syntaxes);
361                 status = push_syntax_id(blob->data + (*offset) + 4, &pkt->ctx_list[i].abstract_syntax);
362                 if (!NT_STATUS_IS_OK(status)) {
363                         return status;
364                 }
365                 (*offset) += 24;
366                 for (j=0;j<pkt->ctx_list[i].num_transfer_syntaxes;j++) {
367                         status = push_syntax_id(blob->data + (*offset), 
368                                                 &pkt->ctx_list[i].transfer_syntaxes[j]);
369                         if (!NT_STATUS_IS_OK(status)) {
370                                 return status;
371                         }
372                         (*offset) += 20;
373                 }
374         }
375
376         return NT_STATUS_OK;
377 }
378
379 /* 
380    push a dcerpc_request into a blob
381 */
382 static NTSTATUS dcerpc_push_request(DATA_BLOB *blob, uint32 *offset,
383                                     struct dcerpc_hdr *hdr,
384                                     struct dcerpc_request *pkt)
385 {
386         SIVAL(blob->data, (*offset) + 0, pkt->alloc_hint);
387         SSVAL(blob->data, (*offset) + 4, pkt->context_id);
388         SSVAL(blob->data, (*offset) + 6, pkt->opnum);
389
390         (*offset) += 8;
391
392         memcpy(blob->data + (*offset), pkt->stub_data.data, pkt->stub_data.length);
393         (*offset) += pkt->stub_data.length;
394
395         memcpy(blob->data + (*offset), pkt->auth_verifier.data, pkt->auth_verifier.length);
396         (*offset) += pkt->auth_verifier.length;
397
398         return NT_STATUS_OK;
399 }
400
401
402 /*
403   work out the wire size of a dcerpc packet 
404 */
405 static uint32 dcerpc_wire_size(struct dcerpc_packet *pkt)
406 {
407         int i;
408         uint32 size = 0;
409
410         size += 16; /* header */
411
412         switch (pkt->hdr.ptype) {
413         case DCERPC_PKT_REQUEST:
414                 size += 8;
415                 size += pkt->in.request.stub_data.length;
416                 size += pkt->in.request.auth_verifier.length;
417                 break;
418
419         case DCERPC_PKT_RESPONSE:
420                 size += 8;
421                 size += pkt->out.response.stub_data.length;
422                 size += pkt->hdr.auth_length;
423                 break;
424
425         case DCERPC_PKT_BIND:
426                 size += 12;
427                 for (i=0;i<pkt->in.bind.num_contexts;i++) {
428                         size += 24;
429                         size += pkt->in.bind.ctx_list[i].num_transfer_syntaxes * 20;
430                 }
431                 size += pkt->hdr.auth_length;
432                 break;
433
434         case DCERPC_PKT_BIND_ACK:
435                 size += 10;
436                 if (pkt->out.bind_ack.secondary_address) {
437                         size += strlen(pkt->out.bind_ack.secondary_address) + 1;
438                 }
439                 size += 4;
440                 size += pkt->out.bind_ack.num_results * 24;
441                 size += pkt->hdr.auth_length;
442                 break;
443         }
444
445         return size;
446 }
447
448 /* 
449    push a dcerpc_packet into a blob. This handles both input and
450    output packets
451 */
452 NTSTATUS dcerpc_push(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, struct dcerpc_packet *pkt)
453 {
454         uint32 offset = 0;
455         uint32 wire_size;
456         NTSTATUS status;
457
458         /* work out how big the packet will be on the wire */
459         wire_size = dcerpc_wire_size(pkt);
460
461         (*blob) = data_blob_talloc(mem_ctx, NULL, wire_size);
462         if (!blob->data) {
463                 return NT_STATUS_NO_MEMORY;
464         }
465
466         pkt->hdr.frag_length = wire_size;
467
468         dcerpc_push_hdr(blob->data + offset, &pkt->hdr);
469         offset += 16;
470
471         switch (pkt->hdr.ptype) {
472         case DCERPC_PKT_BIND:
473                 status = dcerpc_push_bind(blob, &offset, &pkt->hdr, &pkt->in.bind);
474                 break;
475
476         case DCERPC_PKT_REQUEST:
477                 status = dcerpc_push_request(blob, &offset, &pkt->hdr, &pkt->in.request);
478                 break;
479                 
480         default:
481                 status = NT_STATUS_NET_WRITE_FAULT;
482         }
483
484         return status;
485 }
486
487
488
489
490 /* 
491    fill in the fixed values in a dcerpc header 
492 */
493 static void init_dcerpc_hdr(struct dcerpc_hdr *hdr)
494 {
495         hdr->rpc_vers = 5;
496         hdr->rpc_vers_minor = 0;
497         hdr->drep[0] = 0x10; /* Little endian */
498         hdr->drep[1] = 0;
499         hdr->drep[2] = 0;
500         hdr->drep[3] = 0;
501 }
502
503
504 /* 
505    perform a bind using the given syntax 
506 */
507 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
508                      const struct dcerpc_syntax_id *syntax,
509                      const struct dcerpc_syntax_id *transfer_syntax)
510 {
511         TALLOC_CTX *mem_ctx;
512         struct dcerpc_packet pkt;
513         NTSTATUS status;
514         DATA_BLOB blob;
515         DATA_BLOB blob_out;
516
517         mem_ctx = talloc_init("dcerpc_bind");
518         if (!mem_ctx) {
519                 return NT_STATUS_NO_MEMORY;
520         }
521
522         init_dcerpc_hdr(&pkt.hdr);
523
524         pkt.hdr.ptype = DCERPC_PKT_BIND;
525         pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
526         pkt.hdr.call_id = p->call_id++;
527         pkt.hdr.auth_length = 0;
528
529         pkt.in.bind.max_xmit_frag = 0x2000;
530         pkt.in.bind.max_recv_frag = 0x2000;
531         pkt.in.bind.assoc_group_id = 0;
532         pkt.in.bind.num_contexts = 1;
533         pkt.in.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.in.bind.ctx_list[0]));
534         if (!pkt.in.bind.ctx_list) {
535                 talloc_destroy(mem_ctx);
536                 return NT_STATUS_NO_MEMORY;
537         }
538         pkt.in.bind.ctx_list[0].context_id = 0;
539         pkt.in.bind.ctx_list[0].num_transfer_syntaxes = 1;
540         pkt.in.bind.ctx_list[0].abstract_syntax = *syntax;
541         pkt.in.bind.ctx_list[0].transfer_syntaxes = transfer_syntax;
542
543         pkt.in.bind.auth_verifier = data_blob(NULL, 0);
544
545         status = dcerpc_push(&blob, mem_ctx, &pkt);
546         if (!NT_STATUS_IS_OK(status)) {
547                 talloc_destroy(mem_ctx);
548                 return status;
549         }
550
551         status = dcerpc_raw_packet(p, mem_ctx, &blob, &blob_out);
552         if (!NT_STATUS_IS_OK(status)) {
553                 talloc_destroy(mem_ctx);
554                 return status;
555         }
556
557         status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
558         if (!NT_STATUS_IS_OK(status)) {
559                 talloc_destroy(mem_ctx);
560                 return status;
561         }
562
563         if (pkt.hdr.ptype != DCERPC_PKT_BIND_ACK ||
564             pkt.out.bind_ack.num_results == 0 ||
565             pkt.out.bind_ack.ctx_list[0].result != 0) {
566                 status = NT_STATUS_UNSUCCESSFUL;
567         }
568
569         p->srv_max_xmit_frag = pkt.out.bind_ack.max_xmit_frag;
570         p->srv_max_recv_frag = pkt.out.bind_ack.max_recv_frag;
571
572         talloc_destroy(mem_ctx);
573
574         return status;  
575 }
576
577 /* Perform a bind using the given UUID and version */
578 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
579                             const char *uuid, unsigned version)
580 {
581         struct dcerpc_syntax_id syntax;
582         struct dcerpc_syntax_id transfer_syntax;
583
584         syntax.uuid_str = uuid;
585         syntax.if_version = version;
586
587         transfer_syntax.uuid_str = "8a885d04-1ceb-11c9-9fe8-08002b104860";
588         transfer_syntax.if_version = 2;
589
590         return dcerpc_bind(p, &syntax, &transfer_syntax);
591 }
592
593 /*
594   perform a full request/response pair on a dcerpc pipe
595 */
596 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
597                         uint16 opnum,
598                         TALLOC_CTX *mem_ctx,
599                         DATA_BLOB *stub_data_in,
600                         DATA_BLOB *stub_data_out)
601 {
602         
603         struct dcerpc_packet pkt;
604         NTSTATUS status;
605         DATA_BLOB blob_in, blob_out, payload;
606         uint32 remaining, chunk_size;
607
608         init_dcerpc_hdr(&pkt.hdr);
609
610         remaining = stub_data_in->length;
611
612         /* we can write a full max_recv_frag size, minus the dcerpc
613            request header size */
614         chunk_size = p->srv_max_recv_frag - 24;
615
616         pkt.hdr.ptype = DCERPC_PKT_REQUEST;
617         pkt.hdr.call_id = p->call_id++;
618         pkt.hdr.auth_length = 0;
619         pkt.in.request.alloc_hint = remaining;
620         pkt.in.request.context_id = 0;
621         pkt.in.request.opnum = opnum;
622         pkt.in.request.auth_verifier = data_blob(NULL, 0);
623
624         /* we send a series of pdus without waiting for a reply until
625            the last pdu */
626         while (remaining > chunk_size) {
627                 if (remaining == stub_data_in->length) {
628                         pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST;
629                 } else {
630                         pkt.hdr.pfc_flags = 0;
631                 }
632
633                 pkt.in.request.stub_data.data = stub_data_in->data + 
634                         (stub_data_in->length - remaining);
635                 pkt.in.request.stub_data.length = chunk_size;
636
637                 status = dcerpc_push(&blob_in, mem_ctx, &pkt);
638                 if (!NT_STATUS_IS_OK(status)) {
639                         return status;
640                 }
641                 
642                 status = dcerpc_raw_packet_initial(p, mem_ctx, &blob_in);
643                 if (!NT_STATUS_IS_OK(status)) {
644                         return status;
645                 }               
646
647                 remaining -= chunk_size;
648         }
649
650         /* now we send a pdu with LAST_FRAG sent and get the first
651            part of the reply */
652         if (remaining == stub_data_in->length) {
653                 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
654         } else {
655                 pkt.hdr.pfc_flags = DCERPC_PFC_FLAG_LAST;
656         }
657         pkt.in.request.stub_data.data = stub_data_in->data + 
658                 (stub_data_in->length - remaining);
659         pkt.in.request.stub_data.length = remaining;
660         
661         status = dcerpc_push(&blob_in, mem_ctx, &pkt);
662         if (!NT_STATUS_IS_OK(status)) {
663                 return status;
664         }
665
666         /* send the pdu and get the initial response pdu */
667         status = dcerpc_raw_packet(p, mem_ctx, &blob_in, &blob_out);
668
669         status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
670         if (!NT_STATUS_IS_OK(status)) {
671                 return status;
672         }
673
674         if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
675                 return NT_STATUS_UNSUCCESSFUL;
676         }
677
678         if (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
679                 /* something is badly wrong! */
680                 return NT_STATUS_UNSUCCESSFUL;
681         }
682
683         payload = pkt.out.response.stub_data;
684
685         /* continue receiving fragments */
686         while (!(pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
687                 uint32 length;
688
689                 status = dcerpc_raw_packet_secondary(p, mem_ctx, &blob_out);
690                 if (!NT_STATUS_IS_OK(status)) {
691                         return status;
692                 }
693
694                 status = dcerpc_pull(&blob_out, mem_ctx, &pkt);
695                 if (!NT_STATUS_IS_OK(status)) {
696                         return status;
697                 }
698
699                 if (pkt.hdr.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
700                         /* start of another packet!? */
701                         return NT_STATUS_UNSUCCESSFUL;
702                 }
703
704                 if (pkt.hdr.ptype != DCERPC_PKT_RESPONSE) {
705                         return NT_STATUS_UNSUCCESSFUL;
706                 }
707
708                 length = pkt.out.response.stub_data.length;
709
710                 payload.data = talloc_realloc(mem_ctx, 
711                                               payload.data, 
712                                               payload.length + length);
713                 if (!payload.data) {
714                         return NT_STATUS_NO_MEMORY;
715                 }
716
717                 memcpy(payload.data + payload.length,
718                        pkt.out.response.stub_data.data,
719                        length);
720
721                 payload.length += length;
722         }
723
724         if (stub_data_out) {
725                 *stub_data_out = payload;
726         }
727
728         return status;
729 }
730
731
732 /*
733   a useful helper function for synchronous rpc requests 
734
735   this can be used when you have ndr push/pull functions in the
736   standard format
737 */
738 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
739                             uint32 opnum,
740                             TALLOC_CTX *mem_ctx,
741                             NTSTATUS (*ndr_push)(struct ndr_push *, void *),
742                             NTSTATUS (*ndr_pull)(struct ndr_pull *, void *),
743                             void *struct_ptr)
744 {
745         struct ndr_push *push;
746         struct ndr_pull *pull;
747         NTSTATUS status;
748         DATA_BLOB request, response;
749
750         /* setup for a ndr_push_* call */
751         push = ndr_push_init();
752         if (!push) {
753                 talloc_destroy(mem_ctx);
754                 return NT_STATUS_NO_MEMORY;
755         }
756
757         /* push the structure into a blob */
758         status = ndr_push(push, struct_ptr);
759         if (!NT_STATUS_IS_OK(status)) {
760                 goto failed;
761         }
762
763         /* retrieve the blob */
764         request = ndr_push_blob(push);
765
766         dump_data(10, request.data, request.length);
767
768         /* make the actual dcerpc request */
769         status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
770         if (!NT_STATUS_IS_OK(status)) {
771                 goto failed;
772         }
773
774         /* prepare for ndr_pull_* */
775         pull = ndr_pull_init_blob(&response, mem_ctx);
776         if (!pull) {
777                 goto failed;
778         }
779
780         dump_data(10, pull->data, pull->data_size);
781
782         /* pull the structure from the blob */
783         status = ndr_pull(pull, struct_ptr);
784         if (!NT_STATUS_IS_OK(status)) {
785                 goto failed;
786         }
787
788         if (pull->offset != pull->data_size) {
789                 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
790                 status = NT_STATUS_INFO_LENGTH_MISMATCH;
791                 goto failed;
792         }
793
794 failed:
795         ndr_push_free(push);
796         return status;
797 }
798
799
800 /*
801   a useful function for retrieving the server name we connected to
802 */
803 const char *dcerpc_server_name(struct dcerpc_pipe *p)
804 {
805         return p->tree->session->transport->called.name;
806 }