r12622: Move table.c prototypes to seperate header to prevent circular dependencies
[kamenim/samba.git] / source4 / utils / ndrdump.c
1 /* 
2    Unix SMB/CIFS implementation.
3    SMB torture tester
4    Copyright (C) Andrew Tridgell 2003
5    
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22 #include "lib/cmdline/popt_common.h"
23 #include "system/iconv.h"
24 #include "system/filesys.h"
25 #include "librpc/rpc/dcerpc_table.h"
26
27 static const struct dcerpc_interface_call *find_function(
28         const struct dcerpc_interface_table *p,
29         const char *function)
30 {
31         int i;
32         if (isdigit(function[0])) {
33                 i = strtol(function, NULL, 0);
34                 return &p->calls[i];
35         }
36         for (i=0;i<p->num_calls;i++) {
37                 if (strcmp(p->calls[i].name, function) == 0) {
38                         break;
39                 }
40         }
41         if (i == p->num_calls) {
42                 printf("Function '%s' not found\n", function);
43                 exit(1);
44         }
45         return &p->calls[i];
46 }
47
48
49 static void show_pipes(void)
50 {
51         const struct dcerpc_interface_list *l;
52         printf("\nYou must specify a pipe\n");
53         printf("known pipes are:\n");
54         for (l=librpc_dcerpc_pipes();l;l=l->next) {
55                 if(l->table->helpstring) {
56                         printf("\t%s - %s\n", l->table->name, l->table->helpstring);
57                 } else {
58                         printf("\t%s\n", l->table->name);
59                 }
60         }
61         exit(1);
62 }
63
64 static void show_functions(const struct dcerpc_interface_table *p)
65 {
66         int i;
67         printf("\nYou must specify a function\n");
68         printf("known functions on '%s' are:\n", p->name);
69         for (i=0;i<p->num_calls;i++) {
70                 printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name);
71         }
72         exit(1);
73 }
74
75 static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size)
76 {
77         int num_read, total_len = 0;
78         char buf[255];
79         char *result = NULL;
80
81         while((num_read = read(STDIN_FILENO, buf, 255)) > 0) {
82
83                 if (result) {
84                         result = (char *) talloc_realloc(
85                                 mem_ctx, result, char *, total_len + num_read);
86                 } else {
87                         result = talloc_size(mem_ctx, num_read);
88                 }
89
90                 memcpy(result + total_len, buf, num_read);
91
92                 total_len += num_read;
93         }
94
95         if (size)
96                 *size = total_len;
97
98         return result;
99 }
100
101  int main(int argc, const char *argv[])
102 {
103         const struct dcerpc_interface_table *p;
104         const struct dcerpc_interface_call *f;
105         const char *pipe_name, *function, *inout, *filename;
106         uint8_t *data;
107         size_t size;
108         DATA_BLOB blob;
109         struct ndr_pull *ndr_pull;
110         struct ndr_print *ndr_print;
111         TALLOC_CTX *mem_ctx;
112         int flags;
113         poptContext pc;
114         NTSTATUS status;
115         void *st;
116         void *v_st;
117         const char *ctx_filename = NULL;
118         BOOL validate = False;
119         BOOL dumpdata = False;
120         int opt;
121         struct poptOption long_options[] = {
122                 {"context-file", 'c', POPT_ARG_STRING, &ctx_filename, 0, "In-filename to parse first", "CTX-FILE" },
123                 {"validate", 0, POPT_ARG_NONE, &validate, 0, "try to validate the data", NULL },        
124                 {"dump-data", 0, POPT_ARG_NONE, &dumpdata, 0, "dump the hex data", NULL },      
125                 POPT_COMMON_SAMBA
126                 POPT_AUTOHELP
127                 POPT_TABLEEND
128         };
129
130         dcerpc_table_init();
131
132         pc = poptGetContext("ndrdump", argc, argv, long_options, 0);
133         
134         poptSetOtherOptionHelp(
135                 pc, "<pipe|uuid> <function> <inout> [<filename>]");
136
137         while ((opt = poptGetNextOpt(pc)) != -1) {
138         }
139
140         pipe_name = poptGetArg(pc);
141
142         if (!pipe_name) {
143                 poptPrintUsage(pc, stderr, 0);
144                 show_pipes();
145                 exit(1);
146         }
147
148         p = idl_iface_by_name(pipe_name);
149
150         if (!p) {
151                 struct GUID uuid;
152
153                 status = GUID_from_string(pipe_name, &uuid);
154
155                 if (NT_STATUS_IS_OK(status)) {
156                         p = idl_iface_by_uuid(&uuid);
157                 }
158
159                 if (!p) {
160                         printf("Unknown pipe or UUID '%s'\n", pipe_name);
161                         exit(1);
162                 }
163         }
164
165         function = poptGetArg(pc);
166         inout = poptGetArg(pc);
167         filename = poptGetArg(pc);
168
169         if (!function || !inout) {
170                 poptPrintUsage(pc, stderr, 0);
171                 show_functions(p);
172                 exit(1);
173         }
174
175         if (strcmp(inout, "in") == 0 ||
176             strcmp(inout, "request") == 0) {
177                 flags = NDR_IN;
178         } else if (strcmp(inout, "out") == 0 ||
179                    strcmp(inout, "response") == 0) {
180                 flags = NDR_OUT;
181         } else {
182                 printf("Bad inout value '%s'\n", inout);
183                 exit(1);
184         }
185
186         f = find_function(p, function);
187
188         mem_ctx = talloc_init("ndrdump");
189
190         st = talloc_zero_size(mem_ctx, f->struct_size);
191         if (!st) {
192                 printf("Unable to allocate %d bytes\n", (int)f->struct_size);
193                 exit(1);
194         }
195
196         v_st = talloc_zero_size(mem_ctx, f->struct_size);
197         if (!v_st) {
198                 printf("Unable to allocate %d bytes\n", (int)f->struct_size);
199                 exit(1);
200         }
201
202         if (ctx_filename) {
203                 if (flags == NDR_IN) {
204                         printf("Context file can only be used for \"out\" packages\n");
205                         exit(1);
206                 }
207                         
208                 data = (uint8_t *)file_load(ctx_filename, &size, mem_ctx);
209                 if (!data) {
210                         perror(ctx_filename);
211                         exit(1);
212                 }
213
214                 blob.data = data;
215                 blob.length = size;
216
217                 ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
218                 ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
219
220                 status = f->ndr_pull(ndr_pull, NDR_IN, st);
221
222                 if (ndr_pull->offset != ndr_pull->data_size) {
223                         printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - ndr_pull->offset);
224                 }
225
226                 if (!NT_STATUS_IS_OK(status)) {
227                         printf("pull for context file returned %s\n", nt_errstr(status));
228                         exit(1);
229                 }
230                 memcpy(v_st, st, f->struct_size);
231         } 
232
233         if (filename)
234                 data = (uint8_t *)file_load(filename, &size, mem_ctx);
235         else
236                 data = (uint8_t *)stdin_load(mem_ctx, &size);
237
238         if (!data) {
239                 if (filename)
240                         perror(filename);
241                 else
242                         perror("stdin");
243                 exit(1);
244         }
245
246         blob.data = data;
247         blob.length = size;
248
249         ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
250         ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
251
252         status = f->ndr_pull(ndr_pull, flags, st);
253
254         printf("pull returned %s\n", nt_errstr(status));
255
256         if (ndr_pull->offset != ndr_pull->data_size) {
257                 printf("WARNING! %d unread bytes\n", ndr_pull->data_size - ndr_pull->offset);
258                 dump_data(0, ndr_pull->data+ndr_pull->offset, ndr_pull->data_size - ndr_pull->offset);
259         }
260
261         if (dumpdata) {
262                 printf("%d bytes consumed\n", ndr_pull->offset);
263                 dump_data(0, blob.data, blob.length);
264         }
265
266         ndr_print = talloc_zero(mem_ctx, struct ndr_print);
267         ndr_print->print = ndr_print_debug_helper;
268         ndr_print->depth = 1;
269         f->ndr_print(ndr_print, function, flags, st);
270
271         if (!NT_STATUS_IS_OK(status)) {
272                 printf("dump FAILED\n");
273                 exit(1);
274         }
275
276         if (validate) {
277                 DATA_BLOB v_blob;
278                 struct ndr_push *ndr_v_push;
279                 struct ndr_pull *ndr_v_pull;
280                 struct ndr_print *ndr_v_print;
281
282                 ndr_v_push = ndr_push_init_ctx(mem_ctx);
283                 
284                 status = f->ndr_push(ndr_v_push, flags, st);
285                 if (!NT_STATUS_IS_OK(status)) {
286                         printf("validate push FAILED\n");
287                         exit(1);
288                 }
289
290                 v_blob = ndr_push_blob(ndr_v_push);
291
292                 if (dumpdata) {
293                         printf("%ld bytes generated (validate)\n", (long)v_blob.length);
294                         dump_data(0, v_blob.data, v_blob.length);
295                 }
296
297                 ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx);
298                 ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
299
300                 status = f->ndr_pull(ndr_v_pull, flags, v_st);
301                 if (!NT_STATUS_IS_OK(status)) {
302                         printf("validate pull FAILED\n");
303                         exit(1);
304                 }
305
306                 printf("pull returned %s\n", nt_errstr(status));
307
308                 if (ndr_v_pull->offset != ndr_v_pull->data_size) {
309                         printf("WARNING! %d unread bytes in validation\n", ndr_v_pull->data_size - ndr_v_pull->offset);
310                         dump_data(0, ndr_v_pull->data+ndr_v_pull->offset, ndr_v_pull->data_size - ndr_v_pull->offset);
311                 }
312
313                 ndr_v_print = talloc_zero(mem_ctx, struct ndr_print);
314                 ndr_v_print->print = ndr_print_debug_helper;
315                 ndr_v_print->depth = 1;
316                 f->ndr_print(ndr_v_print, function, flags, v_st);
317
318                 if (blob.length != v_blob.length) {
319                         printf("WARNING! orig bytes:%ld validated pushed bytes:%ld\n", (long)blob.length, (long)v_blob.length);
320                 }
321
322                 if (ndr_pull->offset != ndr_v_pull->offset) {
323                         printf("WARNING! orig pulled bytes:%d validated pulled bytes:%d\n", ndr_pull->offset, ndr_v_pull->offset);
324                 }
325         }
326
327         printf("dump OK\n");
328
329         talloc_free(mem_ctx);
330
331         poptFreeContext(pc);
332         
333         return 0;
334 }