ctdb-recovery: Consolidate node state
[Samba.git] / librpc / tools / ndrdump.c
blobbd4f277607b26beb72a69d4e8e5cdf8df185ab96
1 /*
2 Unix SMB/CIFS implementation.
3 SMB torture tester
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) Jelmer Vernooij 2006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "system/filesys.h"
23 #include "system/locale.h"
24 #include "librpc/ndr/libndr.h"
25 #include "librpc/ndr/ndr_table.h"
26 #include "librpc/gen_ndr/ndr_dcerpc.h"
27 #include "lib/cmdline/popt_common.h"
28 #include "param/param.h"
30 static const struct ndr_interface_call *find_function(
31 const struct ndr_interface_table *p,
32 const char *function)
34 int i;
35 if (isdigit(function[0])) {
36 i = strtol(function, NULL, 0);
37 return &p->calls[i];
39 for (i=0;i<p->num_calls;i++) {
40 if (strcmp(p->calls[i].name, function) == 0) {
41 break;
44 if (i == p->num_calls) {
45 printf("Function '%s' not found\n", function);
46 exit(1);
48 return &p->calls[i];
52 * Find a public structure on the pipe and return it as if it were
53 * a function (as the rest of ndrdump is based around functions)
55 static const struct ndr_interface_call *find_struct(
56 const struct ndr_interface_table *p,
57 const char *struct_name,
58 struct ndr_interface_call *out_buffer)
60 int i;
61 for (i=0;i<p->num_public_structs;i++) {
62 if (strcmp(p->public_structs[i].name, struct_name) == 0) {
63 break;
66 if (i == p->num_public_structs) {
67 printf("Public structure '%s' not found\n", struct_name);
68 exit(1);
70 *out_buffer = (struct ndr_interface_call) {
71 .name = p->public_structs[i].name,
72 .struct_size = p->public_structs[i].struct_size,
73 .ndr_pull = p->public_structs[i].ndr_pull,
74 .ndr_push = p->public_structs[i].ndr_push,
75 .ndr_print = p->public_structs[i].ndr_print
77 return out_buffer;
80 _NORETURN_ static void show_pipes(void)
82 const struct ndr_interface_list *l;
83 printf("\nYou must specify a pipe\n");
84 printf("known pipes are:\n");
85 for (l=ndr_table_list();l;l=l->next) {
86 if(l->table->helpstring) {
87 printf("\t%s - %s\n", l->table->name, l->table->helpstring);
88 } else {
89 printf("\t%s\n", l->table->name);
92 exit(1);
95 _NORETURN_ static void show_functions(const struct ndr_interface_table *p)
97 int i;
98 printf("\nYou must specify a function\n");
99 printf("known functions on '%s' are:\n", p->name);
100 for (i=0;i<p->num_calls;i++) {
101 printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name);
103 printf("known public structures on '%s' are:\n", p->name);
104 for (i=0;i<p->num_public_structs;i++) {
105 printf("\t%s\n", p->public_structs[i].name);
107 exit(1);
110 static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size)
112 int num_read, total_len = 0;
113 char buf[255];
114 char *result = NULL;
116 while((num_read = read(STDIN_FILENO, buf, 255)) > 0) {
118 if (result) {
119 result = talloc_realloc(
120 mem_ctx, result, char, total_len + num_read);
121 } else {
122 result = talloc_array(mem_ctx, char, num_read);
125 memcpy(result + total_len, buf, num_read);
127 total_len += num_read;
130 if (size)
131 *size = total_len;
133 return result;
136 static const struct ndr_interface_table *load_iface_from_plugin(const char *plugin, const char *pipe_name)
138 const struct ndr_interface_table *p;
139 void *handle;
140 char *symbol;
142 handle = dlopen(plugin, RTLD_NOW);
143 if (handle == NULL) {
144 printf("%s: Unable to open: %s\n", plugin, dlerror());
145 return NULL;
148 symbol = talloc_asprintf(NULL, "ndr_table_%s", pipe_name);
149 p = (const struct ndr_interface_table *)dlsym(handle, symbol);
151 if (!p) {
152 printf("%s: Unable to find DCE/RPC interface table for '%s': %s\n", plugin, pipe_name, dlerror());
153 talloc_free(symbol);
154 dlclose(handle);
155 return NULL;
158 talloc_free(symbol);
160 return p;
163 static void ndrdump_data(uint8_t *d, uint32_t l, bool force)
165 dump_data_file(d, l, !force, stdout);
168 static NTSTATUS ndrdump_pull_and_print_pipes(const char *function,
169 struct ndr_pull *ndr_pull,
170 struct ndr_print *ndr_print,
171 const struct ndr_interface_call_pipes *pipes)
173 NTSTATUS status;
174 enum ndr_err_code ndr_err;
175 uint32_t i;
177 for (i=0; i < pipes->num_pipes; i++) {
178 uint64_t idx = 0;
179 while (true) {
180 void *saved_mem_ctx;
181 uint32_t *count;
182 void *c;
183 char *n;
185 c = talloc_zero_size(ndr_pull, pipes->pipes[i].chunk_struct_size);
186 talloc_set_name(c, "struct %s", pipes->pipes[i].name);
188 * Note: the first struct member is always
189 * 'uint32_t count;'
191 count = (uint32_t *)c;
193 n = talloc_asprintf(c, "%s: %s[%llu]",
194 function, pipes->pipes[i].name,
195 (unsigned long long)idx);
197 saved_mem_ctx = ndr_pull->current_mem_ctx;
198 ndr_pull->current_mem_ctx = c;
199 ndr_err = pipes->pipes[i].ndr_pull(ndr_pull, NDR_SCALARS, c);
200 ndr_pull->current_mem_ctx = saved_mem_ctx;
201 status = ndr_map_error2ntstatus(ndr_err);
203 printf("pull returned %s\n", nt_errstr(status));
204 if (!NT_STATUS_IS_OK(status)) {
205 talloc_free(c);
206 return status;
208 pipes->pipes[i].ndr_print(ndr_print, n, c);
209 talloc_free(c);
210 if (*count == 0) {
211 break;
213 idx++;
217 return NT_STATUS_OK;
220 static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
222 /* This is here so that you can turn ndr printing off for the purposes
223 of benchmarking ndr parsing. */
226 int main(int argc, const char *argv[])
228 const struct ndr_interface_table *p = NULL;
229 const struct ndr_interface_call *f;
230 struct ndr_interface_call f_buffer;
231 const char *pipe_name = NULL;
232 const char *filename = NULL;
234 * The format type:
235 * in: a request
236 * out: a response
237 * struct: a public structure
239 const char *type = NULL;
241 * Format is either the name of the decoding function or the
242 * name of a public structure
244 const char *format = NULL;
245 uint8_t *data;
246 size_t size;
247 DATA_BLOB blob;
248 struct ndr_pull *ndr_pull;
249 struct ndr_print *ndr_print;
250 TALLOC_CTX *mem_ctx;
251 int flags = 0;
252 poptContext pc;
253 NTSTATUS status;
254 enum ndr_err_code ndr_err;
255 void *st;
256 void *v_st;
257 const char *ctx_filename = NULL;
258 const char *plugin = NULL;
259 bool validate = false;
260 bool dumpdata = false;
261 bool assume_ndr64 = false;
262 bool quiet = false;
263 bool hex_input = false;
264 int opt;
265 enum {OPT_CONTEXT_FILE=1000, OPT_VALIDATE, OPT_DUMP_DATA, OPT_LOAD_DSO, OPT_NDR64, OPT_QUIET, OPT_HEX_INPUT};
266 struct poptOption long_options[] = {
267 POPT_AUTOHELP
268 {"context-file", 'c', POPT_ARG_STRING, NULL, OPT_CONTEXT_FILE, "In-filename to parse first", "CTX-FILE" },
269 {"validate", 0, POPT_ARG_NONE, NULL, OPT_VALIDATE, "try to validate the data", NULL },
270 {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMP_DATA, "dump the hex data", NULL },
271 {"load-dso", 'l', POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL },
272 {"ndr64", 0, POPT_ARG_NONE, NULL, OPT_NDR64, "Assume NDR64 data", NULL },
273 {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, "Don't actually dump anything", NULL },
274 {"hex-input", 0, POPT_ARG_NONE, NULL, OPT_HEX_INPUT, "Read the input file in as a hex dump", NULL },
275 POPT_COMMON_SAMBA
276 POPT_COMMON_VERSION
277 { NULL }
279 uint32_t highest_ofs;
280 struct dcerpc_sec_verification_trailer *sec_vt = NULL;
282 ndr_table_init();
284 /* Initialise samba stuff */
285 smb_init_locale();
287 setlinebuf(stdout);
289 setup_logging("ndrdump", DEBUG_STDOUT);
291 pc = poptGetContext("ndrdump", argc, argv, long_options, 0);
293 poptSetOtherOptionHelp(
294 pc, "<pipe|uuid> <format> <in|out|struct> [<filename>]");
296 while ((opt = poptGetNextOpt(pc)) != -1) {
297 switch (opt) {
298 case OPT_CONTEXT_FILE:
299 ctx_filename = poptGetOptArg(pc);
300 break;
301 case OPT_VALIDATE:
302 validate = true;
303 break;
304 case OPT_DUMP_DATA:
305 dumpdata = true;
306 break;
307 case OPT_LOAD_DSO:
308 plugin = poptGetOptArg(pc);
309 break;
310 case OPT_NDR64:
311 assume_ndr64 = true;
312 break;
313 case OPT_QUIET:
314 quiet = true;
315 break;
316 case OPT_HEX_INPUT:
317 hex_input = true;
318 break;
322 pipe_name = poptGetArg(pc);
324 if (!pipe_name) {
325 poptPrintUsage(pc, stderr, 0);
326 show_pipes();
327 exit(1);
330 if (plugin != NULL) {
331 p = load_iface_from_plugin(plugin, pipe_name);
333 if (!p) {
334 p = ndr_table_by_name(pipe_name);
337 if (!p) {
338 struct GUID uuid;
340 status = GUID_from_string(pipe_name, &uuid);
342 if (NT_STATUS_IS_OK(status)) {
343 p = ndr_table_by_uuid(&uuid);
347 if (!p) {
348 printf("Unknown pipe or UUID '%s'\n", pipe_name);
349 exit(1);
352 format = poptGetArg(pc);
353 type = poptGetArg(pc);
354 filename = poptGetArg(pc);
356 if (!format || !type) {
357 poptPrintUsage(pc, stderr, 0);
358 show_functions(p);
359 exit(1);
362 if (strcmp(type, "struct") == 0) {
363 flags = 0; /* neither NDR_IN nor NDR_OUT */
364 f = find_struct(p, format, &f_buffer);
365 } else {
366 f = find_function(p, format);
367 if (strcmp(type, "in") == 0 ||
368 strcmp(type, "request") == 0) {
369 flags |= NDR_IN;
370 } else if (strcmp(type, "out") == 0 ||
371 strcmp(type, "response") == 0) {
372 flags |= NDR_OUT;
373 } else {
374 printf("Bad type value '%s'\n", type);
375 exit(1);
380 mem_ctx = talloc_init("ndrdump");
382 st = talloc_zero_size(mem_ctx, f->struct_size);
383 if (!st) {
384 printf("Unable to allocate %d bytes\n", (int)f->struct_size);
385 exit(1);
388 v_st = talloc_zero_size(mem_ctx, f->struct_size);
389 if (!v_st) {
390 printf("Unable to allocate %d bytes\n", (int)f->struct_size);
391 exit(1);
394 if (ctx_filename) {
395 if (flags & NDR_IN) {
396 printf("Context file can only be used for \"out\" packages\n");
397 exit(1);
400 data = (uint8_t *)file_load(ctx_filename, &size, 0, mem_ctx);
401 if (!data) {
402 perror(ctx_filename);
403 exit(1);
406 blob.data = data;
407 blob.length = size;
409 ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
410 if (ndr_pull == NULL) {
411 perror("ndr_pull_init_blob");
412 exit(1);
414 ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
415 if (assume_ndr64) {
416 ndr_pull->flags |= LIBNDR_FLAG_NDR64;
419 ndr_err = f->ndr_pull(ndr_pull, NDR_IN, st);
421 if (ndr_pull->offset > ndr_pull->relative_highest_offset) {
422 highest_ofs = ndr_pull->offset;
423 } else {
424 highest_ofs = ndr_pull->relative_highest_offset;
427 if (highest_ofs != ndr_pull->data_size) {
428 printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - highest_ofs);
431 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
432 status = ndr_map_error2ntstatus(ndr_err);
433 printf("pull for context file returned %s\n", nt_errstr(status));
434 exit(1);
436 memcpy(v_st, st, f->struct_size);
439 if (filename)
440 data = (uint8_t *)file_load(filename, &size, 0, mem_ctx);
441 else
442 data = (uint8_t *)stdin_load(mem_ctx, &size);
444 if (!data) {
445 if (filename)
446 perror(filename);
447 else
448 perror("stdin");
449 exit(1);
452 if (hex_input) {
453 blob = hexdump_to_data_blob(mem_ctx, (char *)data, size);
454 } else {
455 blob.data = data;
456 blob.length = size;
459 ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
460 if (ndr_pull == NULL) {
461 perror("ndr_pull_init_blob");
462 exit(1);
464 ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
465 if (assume_ndr64) {
466 ndr_pull->flags |= LIBNDR_FLAG_NDR64;
469 ndr_print = talloc_zero(mem_ctx, struct ndr_print);
470 if (quiet) {
471 ndr_print->print = ndr_print_dummy;
472 } else {
473 ndr_print->print = ndr_print_printf_helper;
475 ndr_print->depth = 1;
477 ndr_err = ndr_pop_dcerpc_sec_verification_trailer(ndr_pull, mem_ctx, &sec_vt);
478 status = ndr_map_error2ntstatus(ndr_err);
479 if (!NT_STATUS_IS_OK(status)) {
480 printf("ndr_pop_dcerpc_sec_verification_trailer returned %s\n",
481 nt_errstr(status));
484 if (sec_vt != NULL && sec_vt->count.count > 0) {
485 printf("SEC_VT: consumed %d bytes\n",
486 (int)(blob.length - ndr_pull->data_size));
487 if (dumpdata) {
488 ndrdump_data(blob.data + ndr_pull->data_size,
489 blob.length - ndr_pull->data_size,
490 dumpdata);
492 ndr_print_dcerpc_sec_verification_trailer(ndr_print, "SEC_VT", sec_vt);
494 TALLOC_FREE(sec_vt);
496 if (flags & NDR_OUT) {
497 status = ndrdump_pull_and_print_pipes(format,
498 ndr_pull,
499 ndr_print,
500 &f->out_pipes);
501 if (!NT_STATUS_IS_OK(status)) {
502 printf("dump FAILED\n");
503 exit(1);
507 ndr_err = f->ndr_pull(ndr_pull, flags, st);
508 status = ndr_map_error2ntstatus(ndr_err);
510 printf("pull returned %s\n", nt_errstr(status));
512 if (ndr_pull->offset > ndr_pull->relative_highest_offset) {
513 highest_ofs = ndr_pull->offset;
514 } else {
515 highest_ofs = ndr_pull->relative_highest_offset;
518 if (highest_ofs != ndr_pull->data_size) {
519 printf("WARNING! %d unread bytes\n", ndr_pull->data_size - highest_ofs);
520 ndrdump_data(ndr_pull->data+highest_ofs,
521 ndr_pull->data_size - highest_ofs,
522 dumpdata);
525 if (dumpdata) {
526 printf("%d bytes consumed\n", highest_ofs);
527 ndrdump_data(blob.data, blob.length, dumpdata);
530 f->ndr_print(ndr_print, format, flags, st);
532 if (!NT_STATUS_IS_OK(status)) {
533 printf("dump FAILED\n");
534 exit(1);
537 if (flags & NDR_IN) {
538 status = ndrdump_pull_and_print_pipes(format,
539 ndr_pull,
540 ndr_print,
541 &f->in_pipes);
542 if (!NT_STATUS_IS_OK(status)) {
543 printf("dump FAILED\n");
544 exit(1);
548 if (validate) {
549 DATA_BLOB v_blob;
550 struct ndr_push *ndr_v_push;
551 struct ndr_pull *ndr_v_pull;
552 struct ndr_print *ndr_v_print;
553 uint32_t highest_v_ofs;
554 uint32_t i;
555 uint8_t byte_a, byte_b;
556 bool differ;
558 ndr_v_push = ndr_push_init_ctx(mem_ctx);
559 if (ndr_v_push == NULL) {
560 printf("No memory\n");
561 exit(1);
564 if (assume_ndr64) {
565 ndr_v_push->flags |= LIBNDR_FLAG_NDR64;
568 ndr_err = f->ndr_push(ndr_v_push, flags, st);
569 status = ndr_map_error2ntstatus(ndr_err);
570 printf("push returned %s\n", nt_errstr(status));
571 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
572 printf("validate push FAILED\n");
573 exit(1);
576 v_blob = ndr_push_blob(ndr_v_push);
578 if (dumpdata) {
579 printf("%ld bytes generated (validate)\n", (long)v_blob.length);
580 ndrdump_data(v_blob.data, v_blob.length, dumpdata);
583 ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx);
584 if (ndr_v_pull == NULL) {
585 perror("ndr_pull_init_blob");
586 exit(1);
588 ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
590 ndr_err = f->ndr_pull(ndr_v_pull, flags, v_st);
591 status = ndr_map_error2ntstatus(ndr_err);
592 printf("pull returned %s\n", nt_errstr(status));
593 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
594 printf("validate pull FAILED\n");
595 exit(1);
598 if (ndr_v_pull->offset > ndr_v_pull->relative_highest_offset) {
599 highest_v_ofs = ndr_v_pull->offset;
600 } else {
601 highest_v_ofs = ndr_v_pull->relative_highest_offset;
604 if (highest_v_ofs != ndr_v_pull->data_size) {
605 printf("WARNING! %d unread bytes in validation\n",
606 ndr_v_pull->data_size - highest_v_ofs);
607 ndrdump_data(ndr_v_pull->data + highest_v_ofs,
608 ndr_v_pull->data_size - highest_v_ofs,
609 dumpdata);
612 ndr_v_print = talloc_zero(mem_ctx, struct ndr_print);
613 ndr_v_print->print = ndr_print_debug_helper;
614 ndr_v_print->depth = 1;
615 f->ndr_print(ndr_v_print,
616 format,
617 flags, v_st);
619 if (blob.length != v_blob.length) {
620 printf("WARNING! orig bytes:%llu validated pushed bytes:%llu\n",
621 (unsigned long long)blob.length, (unsigned long long)v_blob.length);
624 if (highest_ofs != highest_v_ofs) {
625 printf("WARNING! orig pulled bytes:%llu validated pulled bytes:%llu\n",
626 (unsigned long long)highest_ofs, (unsigned long long)highest_v_ofs);
629 differ = false;
630 byte_a = 0x00;
631 byte_b = 0x00;
632 for (i=0; i < blob.length; i++) {
633 byte_a = blob.data[i];
635 if (i == v_blob.length) {
636 byte_b = 0x00;
637 differ = true;
638 break;
641 byte_b = v_blob.data[i];
643 if (byte_a != byte_b) {
644 differ = true;
645 break;
648 if (differ) {
649 printf("WARNING! orig and validated differ at byte 0x%02X (%u)\n", i, i);
650 printf("WARNING! orig byte[0x%02X] = 0x%02X validated byte[0x%02X] = 0x%02X\n",
651 i, byte_a, i, byte_b);
655 printf("dump OK\n");
656 talloc_free(mem_ctx);
658 poptFreeContext(pc);
660 return 0;