ctdb-scripts: Do not de-duplicate the interfaces list
[samba.git] / librpc / tools / ndrdump.c
index b7eae70833e332c9f95359cb36c0acdce1d66d65..5a45f0a5d1d536f90ec7703631e8cd30c9849e76 100644 (file)
@@ -1,39 +1,49 @@
-/* 
+/*
    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 <http://www.gnu.org/licenses/>.
 */
 
 #include "includes.h"
+#include "lib/util/util_file.h"
 #include "system/filesys.h"
 #include "system/locale.h"
 #include "librpc/ndr/libndr.h"
 #include "librpc/ndr/ndr_table.h"
 #include "librpc/gen_ndr/ndr_dcerpc.h"
-#include "lib/cmdline/popt_common.h"
+#include "lib/cmdline/cmdline.h"
 #include "param/param.h"
+#include "lib/util/base64.h"
 
 static const struct ndr_interface_call *find_function(
        const struct ndr_interface_table *p,
        const char *function)
 {
-       int i;
+       unsigned int i;
        if (isdigit(function[0])) {
-               i = strtol(function, NULL, 0);
+               char *eptr = NULL;
+               i = strtoul(function, &eptr, 0);
+               if (i >= p->num_calls
+                   || eptr == NULL
+                   || eptr[0] != '\0') {
+                       printf("Function number '%s' not found\n",
+                              function);
+                       exit(1);
+               }
                return &p->calls[i];
        }
        for (i=0;i<p->num_calls;i++) {
@@ -48,6 +58,50 @@ static const struct ndr_interface_call *find_function(
        return &p->calls[i];
 }
 
+/*
+ * Find a public structure on the pipe and return it as if it were
+ * a function (as the rest of ndrdump is based around functions)
+ */
+static const struct ndr_interface_call *find_struct(
+       const struct ndr_interface_table *p,
+       const char *struct_name,
+       struct ndr_interface_call *out_buffer)
+{
+       unsigned int i;
+       const struct ndr_interface_public_struct *public_struct = NULL;
+       if (isdigit(struct_name[0])) {
+               char *eptr = NULL;
+               i = strtoul(struct_name, &eptr, 0);
+               if (i >= p->num_public_structs
+                   || eptr == NULL
+                   || eptr[0] != '\0') {
+                       printf("Public structure number '%s' not found\n",
+                              struct_name);
+                       exit(1);
+               }
+               public_struct = &p->public_structs[i];
+       } else {
+               for (i=0;i<p->num_public_structs;i++) {
+                       if (strcmp(p->public_structs[i].name, struct_name) == 0) {
+                               break;
+                       }
+               }
+               if (i == p->num_public_structs) {
+                       printf("Public structure '%s' not found\n", struct_name);
+                       exit(1);
+               }
+               public_struct = &p->public_structs[i];
+       }
+       *out_buffer = (struct ndr_interface_call) {
+               .name = public_struct->name,
+               .struct_size = public_struct->struct_size,
+               .ndr_pull = public_struct->ndr_pull,
+               .ndr_push = public_struct->ndr_push,
+               .ndr_print = public_struct->ndr_print
+       };
+       return out_buffer;
+}
+
 _NORETURN_ static void show_pipes(void)
 {
        const struct ndr_interface_list *l;
@@ -71,6 +125,10 @@ _NORETURN_ static void show_functions(const struct ndr_interface_table *p)
        for (i=0;i<p->num_calls;i++) {
                printf("\t0x%02x (%2d) %s\n", i, i, p->calls[i].name);
        }
+       printf("known public structures on '%s' are:\n", p->name);
+       for (i=0;i<p->num_public_structs;i++) {
+               printf("\t%s\n", p->public_structs[i].name);
+       }
        exit(1);
 }
 
@@ -123,7 +181,7 @@ static const struct ndr_interface_table *load_iface_from_plugin(const char *plug
        }
 
        talloc_free(symbol);
-       
+
        return p;
 }
 
@@ -132,12 +190,18 @@ static void ndrdump_data(uint8_t *d, uint32_t l, bool force)
        dump_data_file(d, l, !force, stdout);
 }
 
+static void ndrdump_data_diff(const uint8_t *d1, size_t l1,
+                             const uint8_t *d2, size_t l2,
+                             bool force)
+{
+       dump_data_file_diff(stdout, !force, d1, l1, d2, l2);
+}
+
 static NTSTATUS ndrdump_pull_and_print_pipes(const char *function,
                                struct ndr_pull *ndr_pull,
                                struct ndr_print *ndr_print,
                                const struct ndr_interface_call_pipes *pipes)
 {
-       NTSTATUS status;
        enum ndr_err_code ndr_err;
        uint32_t i;
 
@@ -157,26 +221,27 @@ static NTSTATUS ndrdump_pull_and_print_pipes(const char *function,
                         */
                        count = (uint32_t *)c;
 
-                       n = talloc_asprintf(c, "%s: %s[%llu]",
+                       n = talloc_asprintf(c, "%s: %s[%"PRIu64"]",
                                        function, pipes->pipes[i].name,
-                                       (unsigned long long)idx);
+                                       idx);
 
                        saved_mem_ctx = ndr_pull->current_mem_ctx;
                        ndr_pull->current_mem_ctx = c;
                        ndr_err = pipes->pipes[i].ndr_pull(ndr_pull, NDR_SCALARS, c);
                        ndr_pull->current_mem_ctx = saved_mem_ctx;
-                       status = ndr_map_error2ntstatus(ndr_err);
 
-                       printf("pull returned %s\n", nt_errstr(status));
-                       if (!NT_STATUS_IS_OK(status)) {
+                       printf("pull returned %s\n",
+                              ndr_map_error2string(ndr_err));
+                       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                                talloc_free(c);
-                               return status;
+                               return ndr_map_error2ntstatus(ndr_err);
                        }
                        pipes->pipes[i].ndr_print(ndr_print, n, c);
-                       talloc_free(c);
                        if (*count == 0) {
+                               talloc_free(c);
                                break;
                        }
+                       talloc_free(c);
                        idx++;
                }
        }
@@ -194,14 +259,29 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
 {
        const struct ndr_interface_table *p = NULL;
        const struct ndr_interface_call *f;
-       const char *pipe_name, *function, *inout, *filename;
-       uint8_t *data;
+       struct ndr_interface_call f_buffer;
+       const char *pipe_name = NULL;
+       const char *filename = NULL;
+       /*
+        * The format type:
+        *   in:     a request
+        *   out:    a response
+        *   struct: a public structure
+        */
+       const char *type = NULL;
+       /*
+        * Format is either the name of the decoding function or the
+        * name of a public structure
+        */
+       const char *format = NULL;
+       const char *cmdline_input = NULL;
+       const 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;
+       ndr_flags_type flags = 0;
        poptContext pc;
        NTSTATUS status;
        enum ndr_err_code ndr_err;
@@ -214,24 +294,42 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
        bool assume_ndr64 = false;
        bool quiet = false;
        bool hex_input = false;
+       bool base64_input = false;
+       bool print_after_parse_failure = false;
        int opt;
-       enum {OPT_CONTEXT_FILE=1000, OPT_VALIDATE, OPT_DUMP_DATA, OPT_LOAD_DSO, OPT_NDR64, OPT_QUIET, OPT_HEX_INPUT};
+       enum {
+               OPT_CONTEXT_FILE=1000,
+               OPT_VALIDATE,
+               OPT_DUMP_DATA,
+               OPT_LOAD_DSO,
+               OPT_NDR64,
+               OPT_QUIET,
+               OPT_BASE64_INPUT,
+               OPT_HEX_INPUT,
+               OPT_CMDLINE_INPUT,
+               OPT_PRINT_AFTER_PARSE_FAILURE,
+       };
        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 },
+               {"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", 0, POPT_ARG_STRING, NULL, OPT_LOAD_DSO, "load from shared object file", NULL },
                {"ndr64", 0, POPT_ARG_NONE, NULL, OPT_NDR64, "Assume NDR64 data", NULL },
                {"quiet", 0, POPT_ARG_NONE, NULL, OPT_QUIET, "Don't actually dump anything", NULL },
+               {"base64-input", 0, POPT_ARG_NONE, NULL, OPT_BASE64_INPUT, "Read the input file in as a base64 string", NULL },
                {"hex-input", 0, POPT_ARG_NONE, NULL, OPT_HEX_INPUT, "Read the input file in as a hex dump", NULL },
+               {"input", 0, POPT_ARG_STRING, NULL, OPT_CMDLINE_INPUT, "Provide the input on the command line (use with --base64-input)", "INPUT" },
+               {"print-after-parse-failure", 0, POPT_ARG_NONE, NULL, OPT_PRINT_AFTER_PARSE_FAILURE,
+                "Try to print structures that fail to parse (used to develop parsers, segfaults are likely).", NULL },
                POPT_COMMON_SAMBA
                POPT_COMMON_VERSION
-               { NULL }
+               POPT_TABLEEND
        };
        uint32_t highest_ofs;
        struct dcerpc_sec_verification_trailer *sec_vt = NULL;
-       
+       bool ok;
+
        ndr_table_init();
 
        /* Initialise samba stuff */
@@ -239,12 +337,33 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
 
        setlinebuf(stdout);
 
-       setup_logging("ndrdump", DEBUG_STDOUT);
+       mem_ctx = talloc_init("ndrdump.c/main");
+       if (mem_ctx == NULL) {
+               exit(ENOMEM);
+       }
+
+       ok = samba_cmdline_init(mem_ctx,
+                               SAMBA_CMDLINE_CONFIG_CLIENT,
+                               false /* require_smbconf */);
+       if (!ok) {
+               DBG_ERR("Failed to init cmdline parser!\n");
+               TALLOC_FREE(mem_ctx);
+               exit(1);
+       }
+
+       pc = samba_popt_get_context(getprogname(),
+                                   argc,
+                                   argv,
+                                   long_options,
+                                   0);
+       if (pc == NULL) {
+               DBG_ERR("Failed to setup popt context!\n");
+               TALLOC_FREE(mem_ctx);
+               exit(1);
+       }
 
-       pc = poptGetContext("ndrdump", argc, argv, long_options, 0);
-       
        poptSetOtherOptionHelp(
-               pc, "<pipe|uuid> <function> <inout> [<filename>]");
+               pc, "<pipe|uuid> <format> <in|out|struct> [<filename>]");
 
        while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
@@ -266,9 +385,18 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                case OPT_QUIET:
                        quiet = true;
                        break;
+               case OPT_BASE64_INPUT:
+                       base64_input = true;
+                       break;
                case OPT_HEX_INPUT:
                        hex_input = true;
                        break;
+               case OPT_CMDLINE_INPUT:
+                       cmdline_input = poptGetOptArg(pc);
+                       break;
+               case OPT_PRINT_AFTER_PARSE_FAILURE:
+                       print_after_parse_failure = true;
+                       break;
                }
        }
 
@@ -282,7 +410,7 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
 
        if (plugin != NULL) {
                p = load_iface_from_plugin(plugin, pipe_name);
-       } 
+       }
        if (!p) {
                p = ndr_table_by_name(pipe_name);
        }
@@ -302,61 +430,72 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                exit(1);
        }
 
-       function = poptGetArg(pc);
-       inout = poptGetArg(pc);
+       format = poptGetArg(pc);
+       type = poptGetArg(pc);
        filename = poptGetArg(pc);
 
-       if (!function || !inout) {
+       if (!format || !type) {
                poptPrintUsage(pc, stderr, 0);
                show_functions(p);
                exit(1);
        }
 
-       f = find_function(p, function);
-
-       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;
+       if (strcmp(type, "struct") == 0) {
+               flags = NDR_SCALARS|NDR_BUFFERS; /* neither NDR_IN nor NDR_OUT */
+               f = find_struct(p, format, &f_buffer);
        } else {
-               printf("Bad inout value '%s'\n", inout);
-               exit(1);
+               f = find_function(p, format);
+               if (strcmp(type, "in") == 0 ||
+                   strcmp(type, "request") == 0) {
+                       flags |= NDR_IN;
+               } else if (strcmp(type, "out") == 0 ||
+                          strcmp(type, "response") == 0) {
+                       flags |= NDR_OUT;
+               } else {
+                       printf("Bad type value '%s'\n", type);
+                       exit(1);
+               }
        }
 
-       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);
+               printf("Unable to allocate %zu bytes for %s structure\n",
+                      f->struct_size,
+                      f->name);
+               TALLOC_FREE(mem_ctx);
                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);
+               printf("Unable to allocate %zu bytes for %s validation "
+                      "structure\n",
+                      f->struct_size,
+                      f->name);
+               TALLOC_FREE(mem_ctx);
                exit(1);
        }
 
        if (ctx_filename) {
-               if (flags == NDR_IN) {
+               if (flags & NDR_IN) {
                        printf("Context file can only be used for \"out\" packages\n");
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
-                       
+
                data = (uint8_t *)file_load(ctx_filename, &size, 0, mem_ctx);
                if (!data) {
                        perror(ctx_filename);
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
 
-               blob.data = data;
-               blob.length = size;
+               blob = data_blob_const(data, size);
 
                ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
                if (ndr_pull == NULL) {
                        perror("ndr_pull_init_blob");
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
                ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
@@ -373,21 +512,30 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                }
 
                if (highest_ofs != ndr_pull->data_size) {
-                       printf("WARNING! %d unread bytes while parsing context file\n", ndr_pull->data_size - highest_ofs);
+                       printf("WARNING! %"PRIu32" unread bytes while parsing context file\n", ndr_pull->data_size - highest_ofs);
                }
 
                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);
+                       printf("pull for context file returned %s\n",
+                              ndr_map_error2string(ndr_err));
+                       TALLOC_FREE(mem_ctx);
+                       exit(2);
                }
                memcpy(v_st, st, f->struct_size);
        }
 
-       if (filename)
+       if (filename && cmdline_input) {
+               printf("cannot combine --input with a filename\n");
+               TALLOC_FREE(mem_ctx);
+               exit(1);
+       } else if (cmdline_input) {
+               data = (const uint8_t *)cmdline_input;
+               size = strlen(cmdline_input);
+       } else if (filename) {
                data = (uint8_t *)file_load(filename, &size, 0, mem_ctx);
-       else
+       } else {
                data = (uint8_t *)stdin_load(mem_ctx, &size);
+       }
 
        if (!data) {
                if (filename)
@@ -396,17 +544,35 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                        perror("stdin");
                exit(1);
        }
-       
-       if (hex_input) {
-               blob = hexdump_to_data_blob(mem_ctx, (char *)data, size);
+
+       if (hex_input && base64_input) {
+               printf("cannot combine --hex-input with --base64-input\n");
+               TALLOC_FREE(mem_ctx);
+               exit(1);
+
+       } else if (hex_input && size >= 1 && data[0] != '[') {
+               blob = strhex_to_data_blob(mem_ctx, (const char *)data);
+       } else if (hex_input) {
+               blob = hexdump_to_data_blob(mem_ctx, (const char *)data, size);
+       } else if (base64_input) {
+               /* Use talloc_strndup() to ensure null termination */
+               blob = base64_decode_data_blob_talloc(
+                       mem_ctx,
+                       talloc_strndup(mem_ctx, (const char *)data, size));
        } else {
-               blob.data = data;
-               blob.length = size;
+               blob = data_blob_const(data, size);
+       }
+
+       if (data != NULL && blob.data == NULL) {
+               printf("failed to decode input data\n");
+               TALLOC_FREE(mem_ctx);
+               exit(1);
        }
 
        ndr_pull = ndr_pull_init_blob(&blob, mem_ctx);
        if (ndr_pull == NULL) {
                perror("ndr_pull_init_blob");
+               TALLOC_FREE(mem_ctx);
                exit(1);
        }
        ndr_pull->flags |= LIBNDR_FLAG_REF_ALLOC;
@@ -423,15 +589,14 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
        ndr_print->depth = 1;
 
        ndr_err = ndr_pop_dcerpc_sec_verification_trailer(ndr_pull, mem_ctx, &sec_vt);
-       status = ndr_map_error2ntstatus(ndr_err);
-       if (!NT_STATUS_IS_OK(status)) {
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                printf("ndr_pop_dcerpc_sec_verification_trailer returned %s\n",
-                      nt_errstr(status));
+                      ndr_map_error2string(ndr_err));
        }
 
        if (sec_vt != NULL && sec_vt->count.count > 0) {
-               printf("SEC_VT: consumed %d bytes\n",
-                      (int)(blob.length - ndr_pull->data_size));
+               printf("SEC_VT: consumed %zu bytes\n",
+                      blob.length - ndr_pull->data_size);
                if (dumpdata) {
                        ndrdump_data(blob.data + ndr_pull->data_size,
                                     blob.length - ndr_pull->data_size,
@@ -442,17 +607,21 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
        TALLOC_FREE(sec_vt);
 
        if (flags & NDR_OUT) {
-               status = ndrdump_pull_and_print_pipes(function, ndr_pull, ndr_print, &f->out_pipes);
+               status = ndrdump_pull_and_print_pipes(format,
+                                                     ndr_pull,
+                                                     ndr_print,
+                                                     &f->out_pipes);
                if (!NT_STATUS_IS_OK(status)) {
-                       printf("dump FAILED\n");
-                       exit(1);
+                       printf("pull and dump of OUT pipes FAILED: %s\n",
+                              nt_errstr(status));
+                       TALLOC_FREE(mem_ctx);
+                       exit(2);
                }
        }
 
        ndr_err = f->ndr_pull(ndr_pull, flags, st);
-       status = ndr_map_error2ntstatus(ndr_err);
-
-       printf("pull returned %s\n", nt_errstr(status));
+       printf("pull returned %s\n",
+              ndr_map_error2string(ndr_err));
 
        if (ndr_pull->offset > ndr_pull->relative_highest_offset) {
                highest_ofs = ndr_pull->offset;
@@ -460,33 +629,51 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                highest_ofs = ndr_pull->relative_highest_offset;
        }
 
+       if (dumpdata) {
+               printf("%"PRIu32" bytes consumed\n", highest_ofs);
+               ndrdump_data(blob.data, blob.length, dumpdata);
+       }
+
+       if (!print_after_parse_failure && !NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               TALLOC_FREE(mem_ctx);
+               exit(2);
+       }
+
        if (highest_ofs != ndr_pull->data_size) {
-               printf("WARNING! %d unread bytes\n", ndr_pull->data_size - highest_ofs);
+               printf("WARNING! %"PRIu32" unread bytes\n", ndr_pull->data_size - highest_ofs);
                ndrdump_data(ndr_pull->data+highest_ofs,
                             ndr_pull->data_size - highest_ofs,
                             dumpdata);
        }
 
-       if (dumpdata) {
-               printf("%d bytes consumed\n", highest_ofs);
-               ndrdump_data(blob.data, blob.length, dumpdata);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               printf("WARNING: pull of %s was incomplete, "
+                      "therefore the parse below may SEGFAULT\n",
+                       f->name);
        }
 
-       f->ndr_print(ndr_print, function, flags, st);
-
-       if (!NT_STATUS_IS_OK(status)) {
-               printf("dump FAILED\n");
-               exit(1);
-       }
+       f->ndr_print(ndr_print, f->name, flags, st);
 
        if (flags & NDR_IN) {
-               status = ndrdump_pull_and_print_pipes(function, ndr_pull, ndr_print, &f->in_pipes);
+               status = ndrdump_pull_and_print_pipes(format,
+                                                     ndr_pull,
+                                                     ndr_print,
+                                                     &f->in_pipes);
                if (!NT_STATUS_IS_OK(status)) {
-                       printf("dump FAILED\n");
+                       printf("pull and dump of IN pipes FAILED: %s\n",
+                              nt_errstr(status));
                        exit(1);
                }
        }
 
+       /* Do not proceed to validate if we got an error */
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               printf("dump of failed-to-parse %s complete\n",
+                      f->name);
+               TALLOC_FREE(mem_ctx);
+               exit(2);
+       }
+
        if (validate) {
                DATA_BLOB v_blob;
                struct ndr_push *ndr_v_push;
@@ -508,32 +695,35 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                }
 
                ndr_err = f->ndr_push(ndr_v_push, flags, st);
-               status = ndr_map_error2ntstatus(ndr_err);
-               printf("push returned %s\n", nt_errstr(status));
+               printf("push returned %s\n",
+                      ndr_map_error2string(ndr_err));
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        printf("validate push FAILED\n");
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
 
                v_blob = ndr_push_blob(ndr_v_push);
 
                if (dumpdata) {
-                       printf("%ld bytes generated (validate)\n", (long)v_blob.length);
+                       printf("%zu bytes generated (validate)\n", v_blob.length);
                        ndrdump_data(v_blob.data, v_blob.length, dumpdata);
                }
 
                ndr_v_pull = ndr_pull_init_blob(&v_blob, mem_ctx);
                if (ndr_v_pull == NULL) {
                        perror("ndr_pull_init_blob");
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
                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));
+               printf("pull returned %s\n",
+                      ndr_map_error2string(ndr_err));
                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                        printf("validate pull FAILED\n");
+                       TALLOC_FREE(mem_ctx);
                        exit(1);
                }
 
@@ -544,7 +734,7 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                }
 
                if (highest_v_ofs != ndr_v_pull->data_size) {
-                       printf("WARNING! %d unread bytes in validation\n",
+                       printf("WARNING! %"PRIu32" unread bytes in validation\n",
                               ndr_v_pull->data_size - highest_v_ofs);
                        ndrdump_data(ndr_v_pull->data + highest_v_ofs,
                                     ndr_v_pull->data_size - highest_v_ofs,
@@ -554,16 +744,18 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                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);
+               f->ndr_print(ndr_v_print,
+                            format,
+                            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);
+                       printf("WARNING! orig bytes:%zu validated pushed bytes:%zu\n",
+                              blob.length, v_blob.length);
                }
 
                if (highest_ofs != highest_v_ofs) {
-                       printf("WARNING! orig pulled bytes:%llu validated pulled bytes:%llu\n", 
-                              (unsigned long long)highest_ofs, (unsigned long long)highest_v_ofs);
+                       printf("WARNING! orig pulled bytes:%"PRIu32" validated pulled bytes:%"PRIu32"\n",
+                              highest_ofs, highest_v_ofs);
                }
 
                differ = false;
@@ -586,16 +778,19 @@ static void ndr_print_dummy(struct ndr_print *ndr, const char *format, ...)
                        }
                }
                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",
+                       printf("WARNING! orig and validated differ at byte 0x%02"PRIX32" (%"PRIu32")\n", i, i);
+                       printf("WARNING! orig byte[0x%02"PRIX32"] = 0x%02"PRIX8" validated byte[0x%02"PRIX32"] = 0x%02"PRIX8"\n",
                                i, byte_a, i, byte_b);
+                       ndrdump_data_diff(blob.data, blob.length,
+                                         v_blob.data, v_blob.length,
+                                         dumpdata);
                }
        }
 
        printf("dump OK\n");
-       talloc_free(mem_ctx);
+       TALLOC_FREE(mem_ctx);
 
        poptFreeContext(pc);
-       
+
        return 0;
 }