r884: convert samba4 to use [u]int32_t instead of [u]int32
[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
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(void)
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->call_id = 1;
44         p->auth_info = NULL;
45         p->security_state = NULL;
46         p->flags = 0;
47         p->srv_max_xmit_frag = 0;
48         p->srv_max_recv_frag = 0;
49
50         return p;
51 }
52
53 /* close down a dcerpc over SMB pipe */
54 void dcerpc_pipe_close(struct dcerpc_pipe *p)
55 {
56         if (!p) return;
57         p->reference_count--;
58         if (p->reference_count <= 0) {
59                 if (p->security_state) {
60                         p->security_state->security_end(p->security_state);
61                 }
62                 p->transport.shutdown_pipe(p);
63                 talloc_destroy(p->mem_ctx);
64         }
65 }
66
67 /* we need to be able to get/set the fragment length without doing a full
68    decode */
69 void dcerpc_set_frag_length(DATA_BLOB *blob, uint16 v)
70 {
71         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
72                 SSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
73         } else {
74                 RSSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET, v);
75         }
76 }
77
78 uint16 dcerpc_get_frag_length(const DATA_BLOB *blob)
79 {
80         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
81                 return SVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
82         } else {
83                 return RSVAL(blob->data, DCERPC_FRAG_LEN_OFFSET);
84         }
85 }
86
87 void dcerpc_set_auth_length(DATA_BLOB *blob, uint16 v)
88 {
89         if (CVAL(blob->data,DCERPC_DREP_OFFSET) & DCERPC_DREP_LE) {
90                 SSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
91         } else {
92                 RSSVAL(blob->data, DCERPC_AUTH_LEN_OFFSET, v);
93         }
94 }
95
96
97 /* 
98    parse a data blob into a dcerpc_packet structure. This handles both
99    input and output packets
100 */
101 static NTSTATUS dcerpc_pull(DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
102                             struct dcerpc_packet *pkt)
103 {
104         struct ndr_pull *ndr;
105
106         ndr = ndr_pull_init_blob(blob, mem_ctx);
107         if (!ndr) {
108                 return NT_STATUS_NO_MEMORY;
109         }
110
111         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
112                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
113         }
114
115         return ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
116 }
117
118 /* 
119    parse a possibly signed blob into a dcerpc request packet structure
120 */
121 static NTSTATUS dcerpc_pull_request_sign(struct dcerpc_pipe *p, 
122                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
123                                          struct dcerpc_packet *pkt)
124 {
125         struct ndr_pull *ndr;
126         NTSTATUS status;
127         struct dcerpc_auth auth;
128         DATA_BLOB auth_blob;
129
130         /* non-signed packets are simpler */
131         if (!p->auth_info || !p->security_state) {
132                 return dcerpc_pull(blob, mem_ctx, pkt);
133         }
134
135         ndr = ndr_pull_init_blob(blob, mem_ctx);
136         if (!ndr) {
137                 return NT_STATUS_NO_MEMORY;
138         }
139
140         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
141                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
142         }
143
144         /* pull the basic packet */
145         status = ndr_pull_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
146         if (!NT_STATUS_IS_OK(status)) {
147                 return status;
148         }
149
150         if (pkt->ptype != DCERPC_PKT_RESPONSE) {
151                 return status;
152         }
153
154         auth_blob.length = 8 + pkt->auth_length;
155
156         /* check for a valid length */
157         if (pkt->u.response.stub_and_verifier.length < auth_blob.length) {
158                 return NT_STATUS_INFO_LENGTH_MISMATCH;
159         }
160
161         auth_blob.data = 
162                 pkt->u.response.stub_and_verifier.data + 
163                 pkt->u.response.stub_and_verifier.length - auth_blob.length;
164         pkt->u.response.stub_and_verifier.length -= auth_blob.length;
165
166         /* pull the auth structure */
167         ndr = ndr_pull_init_blob(&auth_blob, mem_ctx);
168         if (!ndr) {
169                 return NT_STATUS_NO_MEMORY;
170         }
171
172         if (! (CVAL(blob->data, DCERPC_DREP_OFFSET) & DCERPC_DREP_LE)) {
173                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
174         }
175
176         status = ndr_pull_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, &auth);
177         if (!NT_STATUS_IS_OK(status)) {
178                 return status;
179         }
180
181
182         /* check signature or unseal the packet */
183         switch (p->auth_info->auth_level) {
184         case DCERPC_AUTH_LEVEL_PRIVACY:
185                 status = p->security_state->unseal_packet(p->security_state, 
186                                                           mem_ctx, 
187                                                           pkt->u.response.stub_and_verifier.data, 
188                                                           pkt->u.response.stub_and_verifier.length, 
189                                                           &auth.credentials);
190                 break;
191
192         case DCERPC_AUTH_LEVEL_INTEGRITY:
193                 status = p->security_state->check_packet(p->security_state, 
194                                                          mem_ctx, 
195                                                          pkt->u.response.stub_and_verifier.data, 
196                                                          pkt->u.response.stub_and_verifier.length, 
197                                                          &auth.credentials);
198                 break;
199
200         case DCERPC_AUTH_LEVEL_NONE:
201                 break;
202
203         default:
204                 status = NT_STATUS_INVALID_LEVEL;
205                 break;
206         }
207
208         /* remove the indicated amount of paddiing */
209         if (pkt->u.response.stub_and_verifier.length < auth.auth_pad_length) {
210                 return NT_STATUS_INFO_LENGTH_MISMATCH;
211         }
212         pkt->u.response.stub_and_verifier.length -= auth.auth_pad_length;
213
214         return status;
215 }
216
217
218 /* 
219    push a dcerpc request packet into a blob, possibly signing it.
220 */
221 static NTSTATUS dcerpc_push_request_sign(struct dcerpc_pipe *p, 
222                                          DATA_BLOB *blob, TALLOC_CTX *mem_ctx, 
223                                          struct dcerpc_packet *pkt)
224 {
225         NTSTATUS status;
226         struct ndr_push *ndr;
227
228         /* non-signed packets are simpler */
229         if (!p->auth_info || !p->security_state) {
230                 return dcerpc_push_auth(blob, mem_ctx, pkt, p->auth_info);
231         }
232
233         ndr = ndr_push_init_ctx(mem_ctx);
234         if (!ndr) {
235                 return NT_STATUS_NO_MEMORY;
236         }
237
238         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
239                 ndr->flags |= LIBNDR_FLAG_BIGENDIAN;
240         }
241
242         status = ndr_push_dcerpc_packet(ndr, NDR_SCALARS|NDR_BUFFERS, pkt);
243         if (!NT_STATUS_IS_OK(status)) {
244                 return status;
245         }
246
247         /* pad to 8 byte multiple */
248         p->auth_info->auth_pad_length = NDR_ALIGN(ndr, 8);
249         ndr_push_zero(ndr, p->auth_info->auth_pad_length);
250
251         /* sign or seal the packet */
252         switch (p->auth_info->auth_level) {
253         case DCERPC_AUTH_LEVEL_PRIVACY:
254                 status = p->security_state->seal_packet(p->security_state, 
255                                                         mem_ctx, 
256                                                         ndr->data + DCERPC_REQUEST_LENGTH, 
257                                                         ndr->offset - DCERPC_REQUEST_LENGTH,
258                                                         &p->auth_info->credentials);
259                 break;
260
261         case DCERPC_AUTH_LEVEL_INTEGRITY:
262                 status = p->security_state->sign_packet(p->security_state, 
263                                                         mem_ctx, 
264                                                         ndr->data + DCERPC_REQUEST_LENGTH, 
265                                                         ndr->offset - DCERPC_REQUEST_LENGTH,
266                                                         &p->auth_info->credentials);
267                 break;
268
269         case DCERPC_AUTH_LEVEL_NONE:
270                 p->auth_info->credentials = data_blob(NULL, 0);
271                 break;
272
273         default:
274                 status = NT_STATUS_INVALID_LEVEL;
275                 break;
276         }
277
278         if (!NT_STATUS_IS_OK(status)) {
279                 return status;
280         }       
281
282         /* add the auth verifier */
283         status = ndr_push_dcerpc_auth(ndr, NDR_SCALARS|NDR_BUFFERS, p->auth_info);
284         if (!NT_STATUS_IS_OK(status)) {
285                 return status;
286         }
287
288         /* extract the whole packet as a blob */
289         *blob = ndr_push_blob(ndr);
290
291         /* fill in the fragment length and auth_length, we can't fill
292            in these earlier as we don't know the signature length (it
293            could be variable length) */
294         dcerpc_set_frag_length(blob, blob->length);
295         dcerpc_set_auth_length(blob, p->auth_info->credentials.length);
296
297         data_blob_free(&p->auth_info->credentials);
298
299         return NT_STATUS_OK;
300 }
301
302
303 /* 
304    fill in the fixed values in a dcerpc header 
305 */
306 static void init_dcerpc_hdr(struct dcerpc_pipe *p, struct dcerpc_packet *pkt)
307 {
308         pkt->rpc_vers = 5;
309         pkt->rpc_vers_minor = 0;
310         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
311                 pkt->drep[0] = 0;
312         } else {
313                 pkt->drep[0] = DCERPC_DREP_LE;
314         }
315         pkt->drep[1] = 0;
316         pkt->drep[2] = 0;
317         pkt->drep[3] = 0;
318 }
319
320
321 /* 
322    perform a bind using the given syntax 
323
324    the auth_info structure is updated with the reply authentication info
325    on success
326 */
327 NTSTATUS dcerpc_bind(struct dcerpc_pipe *p, 
328                      TALLOC_CTX *mem_ctx,
329                      const struct dcerpc_syntax_id *syntax,
330                      const struct dcerpc_syntax_id *transfer_syntax)
331 {
332         struct dcerpc_packet pkt;
333         NTSTATUS status;
334         DATA_BLOB blob;
335         struct dcerpc_syntax_id tsyntax;
336
337         init_dcerpc_hdr(p, &pkt);
338
339         pkt.ptype = DCERPC_PKT_BIND;
340         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
341         pkt.call_id = p->call_id;
342         pkt.auth_length = 0;
343
344         pkt.u.bind.max_xmit_frag = 0x2000;
345         pkt.u.bind.max_recv_frag = 0x2000;
346         pkt.u.bind.assoc_group_id = 0;
347         pkt.u.bind.num_contexts = 1;
348         pkt.u.bind.ctx_list = talloc(mem_ctx, sizeof(pkt.u.bind.ctx_list[0]));
349         if (!pkt.u.bind.ctx_list) {
350                 return NT_STATUS_NO_MEMORY;
351         }
352         pkt.u.bind.ctx_list[0].context_id = 0;
353         pkt.u.bind.ctx_list[0].num_transfer_syntaxes = 1;
354         pkt.u.bind.ctx_list[0].abstract_syntax = *syntax;
355         tsyntax = *transfer_syntax;
356         pkt.u.bind.ctx_list[0].transfer_syntaxes = &tsyntax;
357         pkt.u.bind.auth_info = data_blob(NULL, 0);
358
359         /* construct the NDR form of the packet */
360         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
361         if (!NT_STATUS_IS_OK(status)) {
362                 return status;
363         }
364
365         /* send it on its way */
366         status = p->transport.full_request(p, mem_ctx, &blob, &blob);
367         if (!NT_STATUS_IS_OK(status)) {
368                 return status;
369         }
370
371         /* unmarshall the NDR */
372         status = dcerpc_pull(&blob, mem_ctx, &pkt);
373         if (!NT_STATUS_IS_OK(status)) {
374                 return status;
375         }
376
377         if ((pkt.ptype != DCERPC_PKT_BIND_ACK && pkt.ptype != DCERPC_PKT_ALTER_ACK) ||
378             pkt.u.bind_ack.num_results == 0 ||
379             pkt.u.bind_ack.ctx_list[0].result != 0) {
380                 status = NT_STATUS_UNSUCCESSFUL;
381         }
382
383         if (pkt.ptype != DCERPC_PKT_ALTER_ACK) {
384                 p->srv_max_xmit_frag = pkt.u.bind_ack.max_xmit_frag;
385                 p->srv_max_recv_frag = pkt.u.bind_ack.max_recv_frag;
386         }
387
388         /* the bind_ack might contain a reply set of credentials */
389         if (p->auth_info && pkt.u.bind_ack.auth_info.length) {
390                 status = ndr_pull_struct_blob(&pkt.u.bind_ack.auth_info,
391                                               mem_ctx,
392                                               p->auth_info,
393                                               (ndr_pull_flags_fn_t)ndr_pull_dcerpc_auth);
394         }
395
396         return status;  
397 }
398
399 /* 
400    perform a continued bind (and auth3)
401 */
402 NTSTATUS dcerpc_auth3(struct dcerpc_pipe *p, 
403                       TALLOC_CTX *mem_ctx)
404 {
405         struct dcerpc_packet pkt;
406         NTSTATUS status;
407         DATA_BLOB blob;
408
409         init_dcerpc_hdr(p, &pkt);
410
411         pkt.ptype = DCERPC_PKT_AUTH3;
412         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
413         pkt.call_id = p->call_id++;
414         pkt.auth_length = 0;
415         pkt.u.auth._pad = 0;
416         pkt.u.auth.auth_info = data_blob(NULL, 0);
417
418         /* construct the NDR form of the packet */
419         status = dcerpc_push_auth(&blob, mem_ctx, &pkt, p->auth_info);
420         if (!NT_STATUS_IS_OK(status)) {
421                 return status;
422         }
423
424         /* send it on its way */
425         status = p->transport.initial_request(p, mem_ctx, &blob);
426         if (!NT_STATUS_IS_OK(status)) {
427                 return status;
428         }
429
430         return status;  
431 }
432
433
434 /* perform a dcerpc bind, using the uuid as the key */
435 NTSTATUS dcerpc_bind_byuuid(struct dcerpc_pipe *p, 
436                             TALLOC_CTX *mem_ctx,
437                             const char *uuid, unsigned version)
438 {
439         struct dcerpc_syntax_id syntax;
440         struct dcerpc_syntax_id transfer_syntax;
441         NTSTATUS status;
442
443         status = GUID_from_string(uuid, &syntax.uuid);
444         if (!NT_STATUS_IS_OK(status)) {
445                 DEBUG(2,("Invalid uuid string in dcerpc_bind_byuuid\n"));
446                 return status;
447         }
448         syntax.if_version = version;
449
450         status = GUID_from_string(NDR_GUID, &transfer_syntax.uuid);
451         if (!NT_STATUS_IS_OK(status)) {
452                 return status;
453         }
454         transfer_syntax.if_version = NDR_GUID_VERSION;
455
456         return dcerpc_bind(p, mem_ctx, &syntax, &transfer_syntax);
457 }
458
459 /*
460   perform a full request/response pair on a dcerpc pipe
461 */
462 NTSTATUS dcerpc_request(struct dcerpc_pipe *p, 
463                         uint16 opnum,
464                         TALLOC_CTX *mem_ctx,
465                         DATA_BLOB *stub_data_in,
466                         DATA_BLOB *stub_data_out)
467 {
468         
469         struct dcerpc_packet pkt;
470         NTSTATUS status;
471         DATA_BLOB blob, payload;
472         uint32_t remaining, chunk_size;
473
474         /* allow the application to tell when a fault has happened */
475         p->last_fault_code = 0;
476
477         init_dcerpc_hdr(p, &pkt);
478
479         remaining = stub_data_in->length;
480
481         /* we can write a full max_recv_frag size, minus the dcerpc
482            request header size */
483         chunk_size = p->srv_max_recv_frag - (DCERPC_MAX_SIGN_SIZE+DCERPC_REQUEST_LENGTH);
484
485         pkt.ptype = DCERPC_PKT_REQUEST;
486         pkt.call_id = p->call_id++;
487         pkt.auth_length = 0;
488         pkt.u.request.alloc_hint = remaining;
489         pkt.u.request.context_id = 0;
490         pkt.u.request.opnum = opnum;
491
492         /* we send a series of pdus without waiting for a reply until
493            the last pdu */
494         while (remaining > chunk_size) {
495                 if (remaining == stub_data_in->length) {
496                         pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST;
497                 } else {
498                         pkt.pfc_flags = 0;
499                 }
500
501                 pkt.u.request.stub_and_verifier.data = stub_data_in->data + 
502                         (stub_data_in->length - remaining);
503                 pkt.u.request.stub_and_verifier.length = chunk_size;
504
505                 status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
506                 if (!NT_STATUS_IS_OK(status)) {
507                         return status;
508                 }
509                 
510                 status = p->transport.initial_request(p, mem_ctx, &blob);
511                 if (!NT_STATUS_IS_OK(status)) {
512                         return status;
513                 }               
514
515                 remaining -= chunk_size;
516         }
517
518         /* now we send a pdu with LAST_FRAG sent and get the first
519            part of the reply */
520         if (remaining == stub_data_in->length) {
521                 pkt.pfc_flags = DCERPC_PFC_FLAG_FIRST | DCERPC_PFC_FLAG_LAST;
522         } else {
523                 pkt.pfc_flags = DCERPC_PFC_FLAG_LAST;
524         }
525         pkt.u.request.stub_and_verifier.data = stub_data_in->data + 
526                 (stub_data_in->length - remaining);
527         pkt.u.request.stub_and_verifier.length = remaining;
528
529         status = dcerpc_push_request_sign(p, &blob, mem_ctx, &pkt);
530         if (!NT_STATUS_IS_OK(status)) {
531                 return status;
532         }
533
534         /* send the pdu and get the initial response pdu */
535         status = p->transport.full_request(p, mem_ctx, &blob, &blob);
536         if (!NT_STATUS_IS_OK(status)) {
537                 return status;
538         }
539
540         status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
541         if (!NT_STATUS_IS_OK(status)) {
542                 return status;
543         }
544
545         if (pkt.ptype == DCERPC_PKT_FAULT) {
546                 p->last_fault_code = pkt.u.fault.status;
547                 return NT_STATUS_NET_WRITE_FAULT;
548         }
549
550         if (pkt.ptype != DCERPC_PKT_RESPONSE) {
551                 return NT_STATUS_UNSUCCESSFUL;
552         }
553
554         if (!(pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST)) {
555                 /* something is badly wrong! */
556                 return NT_STATUS_UNSUCCESSFUL;
557         }
558
559         payload = pkt.u.response.stub_and_verifier;
560
561         /* continue receiving fragments */
562         while (!(pkt.pfc_flags & DCERPC_PFC_FLAG_LAST)) {
563                 uint32_t length;
564
565                 status = p->transport.secondary_request(p, mem_ctx, &blob);
566                 if (!NT_STATUS_IS_OK(status)) {
567                         return status;
568                 }
569
570                 status = dcerpc_pull_request_sign(p, &blob, mem_ctx, &pkt);
571                 if (!NT_STATUS_IS_OK(status)) {
572                         return status;
573                 }
574
575                 if (pkt.pfc_flags & DCERPC_PFC_FLAG_FIRST) {
576                         /* start of another packet!? */
577                         return NT_STATUS_UNSUCCESSFUL;
578                 }
579
580                 if (pkt.ptype == DCERPC_PKT_FAULT) {
581                         p->last_fault_code = pkt.u.fault.status;
582                         return NT_STATUS_NET_WRITE_FAULT;
583                 }
584
585                 if (pkt.ptype != DCERPC_PKT_RESPONSE) {
586                         return NT_STATUS_UNSUCCESSFUL;
587                 }
588
589                 length = pkt.u.response.stub_and_verifier.length;
590
591                 payload.data = talloc_realloc(mem_ctx, 
592                                               payload.data, 
593                                               payload.length + length);
594                 if (!payload.data) {
595                         return NT_STATUS_NO_MEMORY;
596                 }
597
598                 memcpy(payload.data + payload.length,
599                        pkt.u.response.stub_and_verifier.data,
600                        length);
601
602                 payload.length += length;
603         }
604
605         if (stub_data_out) {
606                 *stub_data_out = payload;
607         }
608
609         if (!(pkt.drep[0] & DCERPC_DREP_LE)) {
610                 p->flags |= DCERPC_PULL_BIGENDIAN;
611         } else {
612                 p->flags &= ~DCERPC_PULL_BIGENDIAN;
613         }
614
615         return status;
616 }
617
618
619 /*
620   this is a paranoid NDR validator. For every packet we push onto the wire
621   we pull it back again, then push it again. Then we compare the raw NDR data
622   for that to the NDR we initially generated. If they don't match then we know
623   we must have a bug in either the pull or push side of our code
624 */
625 static NTSTATUS dcerpc_ndr_validate_in(TALLOC_CTX *mem_ctx,
626                                        DATA_BLOB blob,
627                                        size_t struct_size,
628                                        NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
629                                        NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
630 {
631         void *st;
632         struct ndr_pull *pull;
633         struct ndr_push *push;
634         NTSTATUS status;
635         DATA_BLOB blob2;
636
637         st = talloc(mem_ctx, struct_size);
638         if (!st) {
639                 return NT_STATUS_NO_MEMORY;
640         }
641
642         pull = ndr_pull_init_blob(&blob, mem_ctx);
643         if (!pull) {
644                 return NT_STATUS_NO_MEMORY;
645         }
646
647         status = ndr_pull(pull, NDR_IN, st);
648         if (!NT_STATUS_IS_OK(status)) {
649                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
650                                       "failed input validation pull - %s",
651                                       nt_errstr(status));
652         }
653
654         push = ndr_push_init_ctx(mem_ctx);
655         if (!push) {
656                 return NT_STATUS_NO_MEMORY;
657         }       
658
659         status = ndr_push(push, NDR_IN, st);
660         if (!NT_STATUS_IS_OK(status)) {
661                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
662                                       "failed input validation push - %s",
663                                       nt_errstr(status));
664         }
665
666         blob2 = ndr_push_blob(push);
667
668         if (!data_blob_equal(&blob, &blob2)) {
669                 DEBUG(3,("original:\n"));
670                 dump_data(3, blob.data, blob.length);
671                 DEBUG(3,("secondary:\n"));
672                 dump_data(3, blob2.data, blob2.length);
673                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
674                                       "failed input validation data - %s",
675                                       nt_errstr(status));
676         }
677
678         return NT_STATUS_OK;
679 }
680
681 /*
682   this is a paranoid NDR input validator. For every packet we pull
683   from the wire we push it back again then pull and push it
684   again. Then we compare the raw NDR data for that to the NDR we
685   initially generated. If they don't match then we know we must have a
686   bug in either the pull or push side of our code
687 */
688 static NTSTATUS dcerpc_ndr_validate_out(TALLOC_CTX *mem_ctx,
689                                         void *struct_ptr,
690                                         size_t struct_size,
691                                         NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
692                                         NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *))
693 {
694         void *st;
695         struct ndr_pull *pull;
696         struct ndr_push *push;
697         NTSTATUS status;
698         DATA_BLOB blob, blob2;
699
700         st = talloc(mem_ctx, struct_size);
701         if (!st) {
702                 return NT_STATUS_NO_MEMORY;
703         }
704         memcpy(st, struct_ptr, struct_size);
705
706         push = ndr_push_init_ctx(mem_ctx);
707         if (!push) {
708                 return NT_STATUS_NO_MEMORY;
709         }       
710
711         status = ndr_push(push, NDR_OUT, struct_ptr);
712         if (!NT_STATUS_IS_OK(status)) {
713                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
714                                       "failed output validation push - %s",
715                                       nt_errstr(status));
716         }
717
718         blob = ndr_push_blob(push);
719
720         pull = ndr_pull_init_blob(&blob, mem_ctx);
721         if (!pull) {
722                 return NT_STATUS_NO_MEMORY;
723         }
724
725         pull->flags |= LIBNDR_FLAG_REF_ALLOC;
726         status = ndr_pull(pull, NDR_OUT, st);
727         if (!NT_STATUS_IS_OK(status)) {
728                 return ndr_pull_error(pull, NDR_ERR_VALIDATE, 
729                                       "failed output validation pull - %s",
730                                       nt_errstr(status));
731         }
732
733         push = ndr_push_init_ctx(mem_ctx);
734         if (!push) {
735                 return NT_STATUS_NO_MEMORY;
736         }       
737
738         status = ndr_push(push, NDR_OUT, st);
739         if (!NT_STATUS_IS_OK(status)) {
740                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
741                                       "failed output validation push2 - %s",
742                                       nt_errstr(status));
743         }
744
745         blob2 = ndr_push_blob(push);
746
747         if (!data_blob_equal(&blob, &blob2)) {
748                 DEBUG(3,("original:\n"));
749                 dump_data(3, blob.data, blob.length);
750                 DEBUG(3,("secondary:\n"));
751                 dump_data(3, blob2.data, blob2.length);
752                 return ndr_push_error(push, NDR_ERR_VALIDATE, 
753                                       "failed output validation data - %s",
754                                       nt_errstr(status));
755         }
756
757         return NT_STATUS_OK;
758 }
759
760 /*
761   a useful helper function for synchronous rpc requests 
762
763   this can be used when you have ndr push/pull functions in the
764   standard format
765 */
766 NTSTATUS dcerpc_ndr_request(struct dcerpc_pipe *p,
767                             uint32_t opnum,
768                             TALLOC_CTX *mem_ctx,
769                             NTSTATUS (*ndr_push)(struct ndr_push *, int, void *),
770                             NTSTATUS (*ndr_pull)(struct ndr_pull *, int, void *),
771                             void *struct_ptr,
772                             size_t struct_size)
773 {
774         struct ndr_push *push;
775         struct ndr_pull *pull;
776         NTSTATUS status;
777         DATA_BLOB request, response;
778
779         /* setup for a ndr_push_* call */
780         push = ndr_push_init();
781         if (!push) {
782                 talloc_destroy(mem_ctx);
783                 return NT_STATUS_NO_MEMORY;
784         }
785
786         if (p->flags & DCERPC_PUSH_BIGENDIAN) {
787                 push->flags |= LIBNDR_FLAG_BIGENDIAN;
788         }
789
790         /* push the structure into a blob */
791         status = ndr_push(push, NDR_IN, struct_ptr);
792         if (!NT_STATUS_IS_OK(status)) {
793                 goto failed;
794         }
795
796         /* retrieve the blob */
797         request = ndr_push_blob(push);
798
799         if (p->flags & DCERPC_DEBUG_VALIDATE_IN) {
800                 status = dcerpc_ndr_validate_in(mem_ctx, request, struct_size, 
801                                                 ndr_push, ndr_pull);
802                 if (!NT_STATUS_IS_OK(status)) {
803                         goto failed;
804                 }
805         }
806
807         DEBUG(10,("rpc request data:\n"));
808         dump_data(10, request.data, request.length);
809
810         /* make the actual dcerpc request */
811         status = dcerpc_request(p, opnum, mem_ctx, &request, &response);
812         if (!NT_STATUS_IS_OK(status)) {
813                 goto failed;
814         }
815
816         /* prepare for ndr_pull_* */
817         pull = ndr_pull_init_blob(&response, mem_ctx);
818         if (!pull) {
819                 goto failed;
820         }
821
822         if (p->flags & DCERPC_PULL_BIGENDIAN) {
823                 pull->flags |= LIBNDR_FLAG_BIGENDIAN;
824         }
825
826         DEBUG(10,("rpc reply data:\n"));
827         dump_data(10, pull->data, pull->data_size);
828
829         /* pull the structure from the blob */
830         status = ndr_pull(pull, NDR_OUT, struct_ptr);
831         if (!NT_STATUS_IS_OK(status)) {
832                 goto failed;
833         }
834
835         /* possibly check the packet signature */
836         
837
838         if (p->flags & DCERPC_DEBUG_VALIDATE_OUT) {
839                 status = dcerpc_ndr_validate_out(mem_ctx, struct_ptr, struct_size, 
840                                                  ndr_push, ndr_pull);
841                 if (!NT_STATUS_IS_OK(status)) {
842                         goto failed;
843                 }
844         }
845
846         if (pull->offset != pull->data_size) {
847                 DEBUG(0,("Warning! %d unread bytes\n", pull->data_size - pull->offset));
848                 status = NT_STATUS_INFO_LENGTH_MISMATCH;
849                 goto failed;
850         }
851
852 failed:
853         ndr_push_free(push);
854         return status;
855 }
856
857
858 /*
859   a useful function for retrieving the server name we connected to
860 */
861 const char *dcerpc_server_name(struct dcerpc_pipe *p)
862 {
863         if (!p->transport.peer_name) {
864                 return "";
865         }
866         return p->transport.peer_name(p);
867 }