From 2fddd2e2d5fb32ff15a170acc443218481986b91 Mon Sep 17 00:00:00 2001 From: Jelmer Vernooij Date: Mon, 13 Oct 2008 15:58:45 +0200 Subject: Share ndrdump implementation. --- librpc/tools/ndrdump.1.xml | 83 +++++++ librpc/tools/ndrdump.c | 461 +++++++++++++++++++++++++++++++++++++ source3/Makefile.in | 2 +- source3/include/proto.h | 1 + source3/lib/util.c | 73 +++++- source3/librpc/ndr/libndr.h | 5 + source3/librpc/ndr/util.c | 6 + source4/librpc/config.mk | 4 +- source4/librpc/tools/ndrdump.1.xml | 83 ------- source4/librpc/tools/ndrdump.c | 459 ------------------------------------ 10 files changed, 625 insertions(+), 552 deletions(-) create mode 100644 librpc/tools/ndrdump.1.xml create mode 100644 librpc/tools/ndrdump.c delete mode 100644 source4/librpc/tools/ndrdump.1.xml delete mode 100644 source4/librpc/tools/ndrdump.c diff --git a/librpc/tools/ndrdump.1.xml b/librpc/tools/ndrdump.1.xml new file mode 100644 index 0000000000..9d66102682 --- /dev/null +++ b/librpc/tools/ndrdump.1.xml @@ -0,0 +1,83 @@ + + + + + + ndrdump + 1 + + + + + ndrdump + DCE/RPC Packet Parser and Dumper + + + + + ndrdump + -c context + pipe + function + in|out + filename + + + ndrdump + pipe + + + ndrdump + + + + + DESCRIPTION + + ndrdump tries to parse the specified filename + using Samba's parser for the specified pipe and function. The + third argument should be + either in or out, depending + on whether the data should be parsed as a request or a reply. + + Running ndrdump without arguments will list the pipes for which + parsers are available. + + Running ndrdump with one argument will list the functions that + Samba can parse for the specified pipe. + + The primary function of ndrdump is debugging Samba's internal + DCE/RPC parsing functions. The file being parsed is usually + one exported by wiresharks Export selected packet bytes + function. + + The context argument can be used to load context data from the request + packet when parsing reply packets (such as array lengths). + + + + + VERSION + + This man page is correct for version 4.0 of the Samba suite. + + + + SEE ALSO + + wireshark, pidl + + + + + AUTHOR + + This utility is part of the Samba suite, which is developed by the global Samba Team. + + ndrdump was written by Andrew Tridgell. + + This manpage was written by Jelmer Vernooij. + + + + diff --git a/librpc/tools/ndrdump.c b/librpc/tools/ndrdump.c new file mode 100644 index 0000000000..3ecf10a167 --- /dev/null +++ b/librpc/tools/ndrdump.c @@ -0,0 +1,461 @@ +/* + Unix SMB/CIFS implementation. + SMB torture tester + Copyright (C) Andrew Tridgell 2003 + Copyright (C) Jelmer Vernooij 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#if (_SAMBA_BUILD_ >= 4) +#include "lib/cmdline/popt_common.h" +#include "system/filesys.h" +#include "system/locale.h" +#include "librpc/ndr/libndr.h" +#include "librpc/ndr/ndr_table.h" +#include "param/param.h" +#else +#define _NORETURN_ +#endif + +static const struct ndr_interface_call *find_function( + const struct ndr_interface_table *p, + const char *function) +{ + int i; + if (isdigit(function[0])) { + i = strtol(function, NULL, 0); + return &p->calls[i]; + } + for (i=0;inum_calls;i++) { + if (strcmp(p->calls[i].name, function) == 0) { + break; + } + } + if (i == p->num_calls) { + printf("Function '%s' not found\n", function); + exit(1); + } + return &p->calls[i]; +} + +#if (_SAMBA_BUILD_ >= 4) + +_NORETURN_ static void show_pipes(void) +{ + const struct ndr_interface_list *l; + printf("\nYou must specify a pipe\n"); + printf("known pipes are:\n"); + for (l=ndr_table_list();l;l=l->next) { + if(l->table->helpstring) { + printf("\t%s - %s\n", l->table->name, l->table->helpstring); + } else { + printf("\t%s\n", l->table->name); + } + } + exit(1); +} + +#endif + +_NORETURN_ static void show_functions(const struct ndr_interface_table *p) +{ + int i; + printf("\nYou must specify a function\n"); + printf("known functions on '%s' are:\n", p->name); + for (i=0;inum_calls;i++) { + printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name); + } + exit(1); +} + +static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size) +{ + int num_read, total_len = 0; + char buf[255]; + char *result = NULL; + + while((num_read = read(STDIN_FILENO, buf, 255)) > 0) { + + if (result) { + result = talloc_realloc( + mem_ctx, result, char, total_len + num_read); + } else { + result = talloc_array(mem_ctx, char, num_read); + } + + memcpy(result + total_len, buf, num_read); + + total_len += num_read; + } + + if (size) + *size = total_len; + + return result; +} + +static const struct ndr_interface_table *load_iface_from_plugin(const char *plugin, const char *pipe_name) +{ + const struct ndr_interface_table *p; + void *handle; + char *symbol; + + handle = dlopen(plugin, RTLD_NOW); + if (handle == NULL) { + printf("%s: Unable to open: %s\n", plugin, dlerror()); + return NULL; + } + + symbol = talloc_asprintf(NULL, "ndr_table_%s", pipe_name); + p = (const struct ndr_interface_table *)dlsym(handle, symbol); + + if (!p) { + printf("%s: Unable to find DCE/RPC interface table for '%s': %s\n", plugin, pipe_name, dlerror()); + talloc_free(symbol); + return NULL; + } + + talloc_free(symbol); + + return p; +} + +static void ndrdump_data(uint8_t *d, uint32_t l, bool force) +{ + if (force) { + dump_data(0, d, l); + } else { + dump_data_skip_zeros(0, d, l); + } +} + + int main(int argc, const char *argv[]) +{ + const struct ndr_interface_table *p = NULL; + const struct ndr_interface_call *f; + const char *pipe_name, *function, *inout, *filename; + uint8_t *data; + size_t size; + DATA_BLOB blob; + struct ndr_pull *ndr_pull; + struct ndr_print *ndr_print; + TALLOC_CTX *mem_ctx; + int flags; + poptContext pc; + NTSTATUS status; + enum ndr_err_code ndr_err; + void *st; + void *v_st; + const char *ctx_filename = NULL; + const char *plugin = NULL; + bool validate = false; + bool dumpdata = false; + int opt; + enum {OPT_CONTEXT_FILE=1000, OPT_VALIDATE, OPT_DUMP_DATA, OPT_LOAD_DSO}; + struct poptOption long_options[] = { + POPT_AUTOHELP + {"context-file", 'c', POPT_ARG_STRING, NULL, OPT_CONTEXT_FILE, "In-filename to parse first", "CTX-FILE" }, + {"validate", 0, POPT_ARG_NONE, NULL, OPT_VALIDATE, "try to validate the data", NULL }, + {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMP_DATA, "dump the hex data", NULL }, + {"load-dso", 'l', POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL }, + POPT_COMMON_SAMBA + POPT_COMMON_VERSION + { NULL } + }; + +#if (_SAMBA_BUILD_ >= 4) + ndr_table_init(); +#else + /* Initialise samba stuff */ + load_case_tables(); + + setlinebuf(stdout); + + dbf = x_stderr; + + setup_logging(argv[0],True); +#endif + + pc = poptGetContext("ndrdump", argc, argv, long_options, 0); + + poptSetOtherOptionHelp( + pc, " []"); + + while ((opt = poptGetNextOpt(pc)) != -1) { + switch (opt) { + case OPT_CONTEXT_FILE: + ctx_filename = poptGetOptArg(pc); + break; + case OPT_VALIDATE: + validate = true; + break; + case OPT_DUMP_DATA: + dumpdata = true; + break; + case OPT_LOAD_DSO: + plugin = poptGetOptArg(pc); + break; + } + } + + pipe_name = poptGetArg(pc); + + if (!pipe_name) { + poptPrintUsage(pc, stderr, 0); +#if (_SAMBA_BUILD_ >= 4) + show_pipes(); +#endif + exit(1); + } + + if (plugin != NULL) { + p = load_iface_from_plugin(plugin, pipe_name); + } +#if (_SAMBA_BUILD_ <= 3) + else { + fprintf(stderr, "Only loading from DSO's supported in Samba 3\n"); + exit(1); + } +#else + if (!p) { + p = ndr_table_by_name(pipe_name); + } + + if (!p) { + struct GUID uuid; + + status = GUID_from_string(pipe_name, &uuid); + + if (NT_STATUS_IS_OK(status)) { + p = ndr_table_by_uuid(&uuid); + } + } +#endif + + if (!p) { + printf("Unknown pipe or UUID '%s'\n", pipe_name); + exit(1); + } + + function = poptGetArg(pc); + inout = poptGetArg(pc); + filename = poptGetArg(pc); + + if (!function || !inout) { + poptPrintUsage(pc, stderr, 0); + show_functions(p); + exit(1); + } + + if (strcmp(inout, "in") == 0 || + strcmp(inout, "request") == 0) { + flags = NDR_IN; + } else if (strcmp(inout, "out") == 0 || + strcmp(inout, "response") == 0) { + flags = NDR_OUT; + } else { + printf("Bad inout value '%s'\n", inout); + exit(1); + } + + f = find_function(p, function); + + mem_ctx = talloc_init("ndrdump"); + + st = talloc_zero_size(mem_ctx, f->struct_size); + if (!st) { + printf("Unable to allocate %d bytes\n", (int)f->struct_size); + exit(1); + } + + v_st = talloc_zero_size(mem_ctx, f->struct_size); + if (!v_st) { + printf("Unable to allocate %d bytes\n", (int)f->struct_size); + exit(1); + } + + if (ctx_filename) { + if (flags == NDR_IN) { + printf("Context file can only be used for \"out\" packages\n"); + exit(1); + } + + data = (uint8_t *)file_load(ctx_filename, &size, 0, mem_ctx); + if (!data) { + perror(ctx_filename); + exit(1); + } + + blob.data = data; + blob.length = size; + + ndr_pull = ndr_pull_init_blob(&blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); + ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; + + ndr_err = f->ndr_pull(ndr_pull, NDR_IN, st); + + if (ndr_pull->offset != ndr_pull->data_size) { + printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - ndr_pull->offset); + } + + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + status = ndr_map_error2ntstatus(ndr_err); + printf("pull for context file returned %s\n", nt_errstr(status)); + exit(1); + } + memcpy(v_st, st, f->struct_size); + } + + if (filename) + data = (uint8_t *)file_load(filename, &size, 0, mem_ctx); + else + data = (uint8_t *)stdin_load(mem_ctx, &size); + + if (!data) { + if (filename) + perror(filename); + else + perror("stdin"); + exit(1); + } + + blob.data = data; + blob.length = size; + + ndr_pull = ndr_pull_init_blob(&blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); + ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; + + ndr_err = f->ndr_pull(ndr_pull, flags, st); + status = ndr_map_error2ntstatus(ndr_err); + + printf("pull returned %s\n", nt_errstr(status)); + + if (ndr_pull->offset != ndr_pull->data_size) { + printf("WARNING! %d unread bytes\n", ndr_pull->data_size - ndr_pull->offset); + ndrdump_data(ndr_pull->data+ndr_pull->offset, + ndr_pull->data_size - ndr_pull->offset, + dumpdata); + } + + if (dumpdata) { + printf("%d bytes consumed\n", ndr_pull->offset); + ndrdump_data(blob.data, blob.length, dumpdata); + } + + ndr_print = talloc_zero(mem_ctx, struct ndr_print); + ndr_print->print = ndr_print_debug_helper; + ndr_print->depth = 1; + f->ndr_print(ndr_print, function, flags, st); + + if (!NT_STATUS_IS_OK(status)) { + printf("dump FAILED\n"); + exit(1); + } + + if (validate) { + DATA_BLOB v_blob; + struct ndr_push *ndr_v_push; + struct ndr_pull *ndr_v_pull; + struct ndr_print *ndr_v_print; + uint32_t i; + uint8_t byte_a, byte_b; + bool differ; + + ndr_v_push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); + + ndr_err = f->ndr_push(ndr_v_push, flags, st); + status = ndr_map_error2ntstatus(ndr_err); + printf("push returned %s\n", nt_errstr(status)); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + printf("validate push FAILED\n"); + exit(1); + } + + v_blob = ndr_push_blob(ndr_v_push); + + if (dumpdata) { + printf("%ld bytes generated (validate)\n", (long)v_blob.length); + ndrdump_data(v_blob.data, v_blob.length, dumpdata); + } + + ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); + ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC; + + ndr_err = f->ndr_pull(ndr_v_pull, flags, v_st); + status = ndr_map_error2ntstatus(ndr_err); + printf("pull returned %s\n", nt_errstr(status)); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + printf("validate pull FAILED\n"); + exit(1); + } + + + if (ndr_v_pull->offset != ndr_v_pull->data_size) { + printf("WARNING! %d unread bytes in validation\n", ndr_v_pull->data_size - ndr_v_pull->offset); + ndrdump_data(ndr_v_pull->data+ndr_v_pull->offset, + ndr_v_pull->data_size - ndr_v_pull->offset, + dumpdata); + } + + ndr_v_print = talloc_zero(mem_ctx, struct ndr_print); + ndr_v_print->print = ndr_print_debug_helper; + ndr_v_print->depth = 1; + f->ndr_print(ndr_v_print, function, flags, v_st); + + if (blob.length != v_blob.length) { + printf("WARNING! orig bytes:%llu validated pushed bytes:%llu\n", + (unsigned long long)blob.length, (unsigned long long)v_blob.length); + } + + if (ndr_pull->offset != ndr_v_pull->offset) { + printf("WARNING! orig pulled bytes:%llu validated pulled bytes:%llu\n", + (unsigned long long)ndr_pull->offset, (unsigned long long)ndr_v_pull->offset); + } + + differ = false; + byte_a = 0x00; + byte_b = 0x00; + for (i=0; i < blob.length; i++) { + byte_a = blob.data[i]; + + if (i == v_blob.length) { + byte_b = 0x00; + differ = true; + break; + } + + byte_b = v_blob.data[i]; + + if (byte_a != byte_b) { + differ = true; + break; + } + } + if (differ) { + printf("WARNING! orig and validated differ at byte 0x%02X (%u)\n", i, i); + printf("WARNING! orig byte[0x%02X] = 0x%02X validated byte[0x%02X] = 0x%02X\n", + i, byte_a, i, byte_b); + } + } + + printf("dump OK\n"); + + talloc_free(mem_ctx); + + poptFreeContext(pc); + + return 0; +} diff --git a/source3/Makefile.in b/source3/Makefile.in index d6c5486528..1685bf141d 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -968,7 +968,7 @@ REPLACETORT_OBJ = @libreplacedir@/test/testsuite.o \ @libreplacedir@/test/main.o \ $(LIBREPLACE_OBJ) -NDRDUMP_OBJ = librpc/tools/ndrdump.o \ +NDRDUMP_OBJ = ../librpc/tools/ndrdump.o \ $(PARAM_OBJ) $(LIBNDR_GEN_OBJ) \ $(LIBSAMBA_OBJ) $(LIB_NONSMBD_OBJ) $(POPT_LIB_OBJ) \ librpc/gen_ndr/ndr_svcctl.o diff --git a/source3/include/proto.h b/source3/include/proto.h index fb6d45befd..7dc0319e7d 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1291,6 +1291,7 @@ enum remote_arch_types get_remote_arch(void); void print_asc(int level, const unsigned char *buf,int len); void dump_data(int level, const unsigned char *buf1,int len); void dump_data_pw(const char *msg, const uchar * data, size_t len); +void dump_data_skip_zeros(int level, const uint8_t *buf, int len); const char *tab_depth(int level, int depth); int str_checksum(const char *s); void zero_free(void *p, size_t size); diff --git a/source3/lib/util.c b/source3/lib/util.c index ec43ea7037..418ae41392 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -2217,25 +2217,60 @@ void print_asc(int level, const unsigned char *buf,int len) DEBUG(level,("%c", isprint(buf[i])?buf[i]:'.')); } -void dump_data(int level, const unsigned char *buf1,int len) +/** + * Write dump of binary data to the log file. + * + * The data is only written if the log level is at least level. + */ +static void _dump_data(int level, const uint8_t *buf, int len, + bool omit_zero_bytes) { - const unsigned char *buf = (const unsigned char *)buf1; int i=0; + const uint8_t empty[16]; + bool skipped = false; + if (len<=0) return; if (!DEBUGLVL(level)) return; - - DEBUGADD(level,("[%03X] ",i)); + + memset(&empty, '\0', 16); + for (i=0;i 0) && + (len > i+16) && + (memcmp(&buf[i], &empty, 16) == 0)) + { + i +=16; + continue; + } + + if (i i+16) && + (memcmp(&buf[i], &empty, 16) == 0)) { + if (!skipped) { + DEBUGADD(level,("skipping zero buffer bytes\n")); + skipped = true; + } + } } } + if (i%16) { int n; n = 16 - (i%16); @@ -2248,8 +2283,32 @@ void dump_data(int level, const unsigned char *buf1,int len) if (n>0) print_asc(level,&buf[i-n],n); DEBUGADD(level,("\n")); } + +} + +/** + * Write dump of binary data to the log file. + * + * The data is only written if the log level is at least level. + */ +_PUBLIC_ void dump_data(int level, const uint8_t *buf, int len) +{ + _dump_data(level, buf, len, false); } +/** + * Write dump of binary data to the log file. + * + * The data is only written if the log level is at least level. + * 16 zero bytes in a row are ommited + */ +_PUBLIC_ void dump_data_skip_zeros(int level, const uint8_t *buf, int len) +{ + _dump_data(level, buf, len, true); +} + + + void dump_data_pw(const char *msg, const uchar * data, size_t len) { #ifdef DEBUG_PASSWORD diff --git a/source3/librpc/ndr/libndr.h b/source3/librpc/ndr/libndr.h index a860f35998..e25a7b8abd 100644 --- a/source3/librpc/ndr/libndr.h +++ b/source3/librpc/ndr/libndr.h @@ -26,6 +26,11 @@ #include "librpc/gen_ndr/misc.h" #include "librpc/gen_ndr/security.h" +/* Samba 3 doesn't use iconv_convenience: */ +extern void *global_loadparm; +extern void *cmdline_lp_ctx; +struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx); + /* this provides definitions for the libcli/rpc/ MSRPC library */ diff --git a/source3/librpc/ndr/util.c b/source3/librpc/ndr/util.c index b85739df69..427292ac70 100644 --- a/source3/librpc/ndr/util.c +++ b/source3/librpc/ndr/util.c @@ -180,3 +180,9 @@ _PUBLIC_ void ndr_print_sockaddr_storage(struct ndr_print *ndr, const char *name ndr->print(ndr, "%-25s: %s", name, print_sockaddr(addr, sizeof(addr), ss)); } +void *global_loadparm; +void *cmdline_lp_ctx; +struct smb_iconv_convenience *lp_iconv_convenience(void *lp_ctx) +{ + return NULL; +} diff --git a/source4/librpc/config.mk b/source4/librpc/config.mk index 4e1ccbb1a7..a481b97a11 100644 --- a/source4/librpc/config.mk +++ b/source4/librpc/config.mk @@ -36,9 +36,9 @@ PRIVATE_DEPENDENCIES = \ # End BINARY ndrdump ################################# -ndrdump_OBJ_FILES = $(librpcsrcdir)/tools/ndrdump.o +ndrdump_OBJ_FILES = ../librpc/tools/ndrdump.o -MANPAGES += $(librpcsrcdir)/tools/ndrdump.1 +MANPAGES += ../librpc/tools/ndrdump.1 ################################################ # Start SUBSYSTEM NDR_COMPRESSION diff --git a/source4/librpc/tools/ndrdump.1.xml b/source4/librpc/tools/ndrdump.1.xml deleted file mode 100644 index 9d66102682..0000000000 --- a/source4/librpc/tools/ndrdump.1.xml +++ /dev/null @@ -1,83 +0,0 @@ - - - - - - ndrdump - 1 - - - - - ndrdump - DCE/RPC Packet Parser and Dumper - - - - - ndrdump - -c context - pipe - function - in|out - filename - - - ndrdump - pipe - - - ndrdump - - - - - DESCRIPTION - - ndrdump tries to parse the specified filename - using Samba's parser for the specified pipe and function. The - third argument should be - either in or out, depending - on whether the data should be parsed as a request or a reply. - - Running ndrdump without arguments will list the pipes for which - parsers are available. - - Running ndrdump with one argument will list the functions that - Samba can parse for the specified pipe. - - The primary function of ndrdump is debugging Samba's internal - DCE/RPC parsing functions. The file being parsed is usually - one exported by wiresharks Export selected packet bytes - function. - - The context argument can be used to load context data from the request - packet when parsing reply packets (such as array lengths). - - - - - VERSION - - This man page is correct for version 4.0 of the Samba suite. - - - - SEE ALSO - - wireshark, pidl - - - - - AUTHOR - - This utility is part of the Samba suite, which is developed by the global Samba Team. - - ndrdump was written by Andrew Tridgell. - - This manpage was written by Jelmer Vernooij. - - - - diff --git a/source4/librpc/tools/ndrdump.c b/source4/librpc/tools/ndrdump.c deleted file mode 100644 index b24868eace..0000000000 --- a/source4/librpc/tools/ndrdump.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - Unix SMB/CIFS implementation. - SMB torture tester - Copyright (C) Andrew Tridgell 2003 - Copyright (C) Jelmer Vernooij 2006 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -#include "includes.h" -#if (_SAMBA_BUILD_ >= 4) -#include "lib/cmdline/popt_common.h" -#include "system/filesys.h" -#include "system/locale.h" -#include "librpc/ndr/libndr.h" -#include "librpc/ndr/ndr_table.h" -#include "param/param.h" -#endif - -static const struct ndr_interface_call *find_function( - const struct ndr_interface_table *p, - const char *function) -{ - int i; - if (isdigit(function[0])) { - i = strtol(function, NULL, 0); - return &p->calls[i]; - } - for (i=0;inum_calls;i++) { - if (strcmp(p->calls[i].name, function) == 0) { - break; - } - } - if (i == p->num_calls) { - printf("Function '%s' not found\n", function); - exit(1); - } - return &p->calls[i]; -} - -#if (_SAMBA_BUILD_ >= 4) - -_NORETURN_ static void show_pipes(void) -{ - const struct ndr_interface_list *l; - printf("\nYou must specify a pipe\n"); - printf("known pipes are:\n"); - for (l=ndr_table_list();l;l=l->next) { - if(l->table->helpstring) { - printf("\t%s - %s\n", l->table->name, l->table->helpstring); - } else { - printf("\t%s\n", l->table->name); - } - } - exit(1); -} - -#endif - -_NORETURN_ static void show_functions(const struct ndr_interface_table *p) -{ - int i; - printf("\nYou must specify a function\n"); - printf("known functions on '%s' are:\n", p->name); - for (i=0;inum_calls;i++) { - printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name); - } - exit(1); -} - -static char *stdin_load(TALLOC_CTX *mem_ctx, size_t *size) -{ - int num_read, total_len = 0; - char buf[255]; - char *result = NULL; - - while((num_read = read(STDIN_FILENO, buf, 255)) > 0) { - - if (result) { - result = talloc_realloc( - mem_ctx, result, char, total_len + num_read); - } else { - result = talloc_array(mem_ctx, char, num_read); - } - - memcpy(result + total_len, buf, num_read); - - total_len += num_read; - } - - if (size) - *size = total_len; - - return result; -} - -static const struct ndr_interface_table *load_iface_from_plugin(const char *plugin, const char *pipe_name) -{ - const struct ndr_interface_table *p; - void *handle; - char *symbol; - - handle = dlopen(plugin, RTLD_NOW); - if (handle == NULL) { - printf("%s: Unable to open: %s\n", plugin, dlerror()); - return NULL; - } - - symbol = talloc_asprintf(NULL, "ndr_table_%s", pipe_name); - p = (const struct ndr_interface_table *)dlsym(handle, symbol); - - if (!p) { - printf("%s: Unable to find DCE/RPC interface table for '%s': %s\n", plugin, pipe_name, dlerror()); - talloc_free(symbol); - return NULL; - } - - talloc_free(symbol); - - return p; -} - -static void ndrdump_data(uint8_t *d, uint32_t l, bool force) -{ - if (force) { - dump_data(0, d, l); - } else { - dump_data_skip_zeros(0, d, l); - } -} - - int main(int argc, const char *argv[]) -{ - const struct ndr_interface_table *p = NULL; - const struct ndr_interface_call *f; - const char *pipe_name, *function, *inout, *filename; - uint8_t *data; - size_t size; - DATA_BLOB blob; - struct ndr_pull *ndr_pull; - struct ndr_print *ndr_print; - TALLOC_CTX *mem_ctx; - int flags; - poptContext pc; - NTSTATUS status; - enum ndr_err_code ndr_err; - void *st; - void *v_st; - const char *ctx_filename = NULL; - const char *plugin = NULL; - bool validate = false; - bool dumpdata = false; - int opt; - enum {OPT_CONTEXT_FILE=1000, OPT_VALIDATE, OPT_DUMP_DATA, OPT_LOAD_DSO}; - struct poptOption long_options[] = { - POPT_AUTOHELP - {"context-file", 'c', POPT_ARG_STRING, NULL, OPT_CONTEXT_FILE, "In-filename to parse first", "CTX-FILE" }, - {"validate", 0, POPT_ARG_NONE, NULL, OPT_VALIDATE, "try to validate the data", NULL }, - {"dump-data", 0, POPT_ARG_NONE, NULL, OPT_DUMP_DATA, "dump the hex data", NULL }, - {"load-dso", 'l', POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL }, - POPT_COMMON_SAMBA - POPT_COMMON_VERSION - { NULL } - }; - -#if (_SAMBA_BUILD_ >= 4) - ndr_table_init(); -#else - /* Initialise samba stuff */ - load_case_tables(); - - setlinebuf(stdout); - - dbf = x_stderr; - - setup_logging(argv[0],True); -#endif - - pc = poptGetContext("ndrdump", argc, argv, long_options, 0); - - poptSetOtherOptionHelp( - pc, " []"); - - while ((opt = poptGetNextOpt(pc)) != -1) { - switch (opt) { - case OPT_CONTEXT_FILE: - ctx_filename = poptGetOptArg(pc); - break; - case OPT_VALIDATE: - validate = true; - break; - case OPT_DUMP_DATA: - dumpdata = true; - break; - case OPT_LOAD_DSO: - plugin = poptGetOptArg(pc); - break; - } - } - - pipe_name = poptGetArg(pc); - - if (!pipe_name) { - poptPrintUsage(pc, stderr, 0); -#if (_SAMBA_BUILD_ >= 4) - show_pipes(); -#endif - exit(1); - } - - if (plugin != NULL) { - p = load_iface_from_plugin(plugin, pipe_name); - } -#if (_SAMBA_BUILD_ <= 3) - else { - fprintf(stderr, "Only loading from DSO's supported in Samba 3\n"); - exit(1); - } -#else - if (!p) { - p = ndr_table_by_name(pipe_name); - } - - if (!p) { - struct GUID uuid; - - status = GUID_from_string(pipe_name, &uuid); - - if (NT_STATUS_IS_OK(status)) { - p = ndr_table_by_uuid(&uuid); - } - } -#endif - - if (!p) { - printf("Unknown pipe or UUID '%s'\n", pipe_name); - exit(1); - } - - function = poptGetArg(pc); - inout = poptGetArg(pc); - filename = poptGetArg(pc); - - if (!function || !inout) { - poptPrintUsage(pc, stderr, 0); - show_functions(p); - exit(1); - } - - if (strcmp(inout, "in") == 0 || - strcmp(inout, "request") == 0) { - flags = NDR_IN; - } else if (strcmp(inout, "out") == 0 || - strcmp(inout, "response") == 0) { - flags = NDR_OUT; - } else { - printf("Bad inout value '%s'\n", inout); - exit(1); - } - - f = find_function(p, function); - - mem_ctx = talloc_init("ndrdump"); - - st = talloc_zero_size(mem_ctx, f->struct_size); - if (!st) { - printf("Unable to allocate %d bytes\n", (int)f->struct_size); - exit(1); - } - - v_st = talloc_zero_size(mem_ctx, f->struct_size); - if (!v_st) { - printf("Unable to allocate %d bytes\n", (int)f->struct_size); - exit(1); - } - - if (ctx_filename) { - if (flags == NDR_IN) { - printf("Context file can only be used for \"out\" packages\n"); - exit(1); - } - - data = (uint8_t *)file_load(ctx_filename, &size, 0, mem_ctx); - if (!data) { - perror(ctx_filename); - exit(1); - } - - blob.data = data; - blob.length = size; - - ndr_pull = ndr_pull_init_blob(&blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); - ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; - - ndr_err = f->ndr_pull(ndr_pull, NDR_IN, st); - - if (ndr_pull->offset != ndr_pull->data_size) { - printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - ndr_pull->offset); - } - - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - status = ndr_map_error2ntstatus(ndr_err); - printf("pull for context file returned %s\n", nt_errstr(status)); - exit(1); - } - memcpy(v_st, st, f->struct_size); - } - - if (filename) - data = (uint8_t *)file_load(filename, &size, 0, mem_ctx); - else - data = (uint8_t *)stdin_load(mem_ctx, &size); - - if (!data) { - if (filename) - perror(filename); - else - perror("stdin"); - exit(1); - } - - blob.data = data; - blob.length = size; - - ndr_pull = ndr_pull_init_blob(&blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); - ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC; - - ndr_err = f->ndr_pull(ndr_pull, flags, st); - status = ndr_map_error2ntstatus(ndr_err); - - printf("pull returned %s\n", nt_errstr(status)); - - if (ndr_pull->offset != ndr_pull->data_size) { - printf("WARNING! %d unread bytes\n", ndr_pull->data_size - ndr_pull->offset); - ndrdump_data(ndr_pull->data+ndr_pull->offset, - ndr_pull->data_size - ndr_pull->offset, - dumpdata); - } - - if (dumpdata) { - printf("%d bytes consumed\n", ndr_pull->offset); - ndrdump_data(blob.data, blob.length, dumpdata); - } - - ndr_print = talloc_zero(mem_ctx, struct ndr_print); - ndr_print->print = ndr_print_debug_helper; - ndr_print->depth = 1; - f->ndr_print(ndr_print, function, flags, st); - - if (!NT_STATUS_IS_OK(status)) { - printf("dump FAILED\n"); - exit(1); - } - - if (validate) { - DATA_BLOB v_blob; - struct ndr_push *ndr_v_push; - struct ndr_pull *ndr_v_pull; - struct ndr_print *ndr_v_print; - uint32_t i; - uint8_t byte_a, byte_b; - bool differ; - - ndr_v_push = ndr_push_init_ctx(mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); - - ndr_err = f->ndr_push(ndr_v_push, flags, st); - status = ndr_map_error2ntstatus(ndr_err); - printf("push returned %s\n", nt_errstr(status)); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - printf("validate push FAILED\n"); - exit(1); - } - - v_blob = ndr_push_blob(ndr_v_push); - - if (dumpdata) { - printf("%ld bytes generated (validate)\n", (long)v_blob.length); - ndrdump_data(v_blob.data, v_blob.length, dumpdata); - } - - ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx, lp_iconv_convenience(cmdline_lp_ctx)); - ndr_v_pull->flags |= LIBNDR_FLAG_REF_ALLOC; - - ndr_err = f->ndr_pull(ndr_v_pull, flags, v_st); - status = ndr_map_error2ntstatus(ndr_err); - printf("pull returned %s\n", nt_errstr(status)); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - printf("validate pull FAILED\n"); - exit(1); - } - - - if (ndr_v_pull->offset != ndr_v_pull->data_size) { - printf("WARNING! %d unread bytes in validation\n", ndr_v_pull->data_size - ndr_v_pull->offset); - ndrdump_data(ndr_v_pull->data+ndr_v_pull->offset, - ndr_v_pull->data_size - ndr_v_pull->offset, - dumpdata); - } - - ndr_v_print = talloc_zero(mem_ctx, struct ndr_print); - ndr_v_print->print = ndr_print_debug_helper; - ndr_v_print->depth = 1; - f->ndr_print(ndr_v_print, function, flags, v_st); - - if (blob.length != v_blob.length) { - printf("WARNING! orig bytes:%llu validated pushed bytes:%llu\n", - (unsigned long long)blob.length, (unsigned long long)v_blob.length); - } - - if (ndr_pull->offset != ndr_v_pull->offset) { - printf("WARNING! orig pulled bytes:%llu validated pulled bytes:%llu\n", - (unsigned long long)ndr_pull->offset, (unsigned long long)ndr_v_pull->offset); - } - - differ = false; - byte_a = 0x00; - byte_b = 0x00; - for (i=0; i < blob.length; i++) { - byte_a = blob.data[i]; - - if (i == v_blob.length) { - byte_b = 0x00; - differ = true; - break; - } - - byte_b = v_blob.data[i]; - - if (byte_a != byte_b) { - differ = true; - break; - } - } - if (differ) { - printf("WARNING! orig and validated differ at byte 0x%02X (%u)\n", i, i); - printf("WARNING! orig byte[0x%02X] = 0x%02X validated byte[0x%02X] = 0x%02X\n", - i, byte_a, i, byte_b); - } - } - - printf("dump OK\n"); - - talloc_free(mem_ctx); - - poptFreeContext(pc); - - return 0; -} -- cgit