added an rpc scanner. This prints messages like this:
authorAndrew Tridgell <tridge@samba.org>
Thu, 27 Nov 2003 05:34:28 +0000 (05:34 +0000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 27 Nov 2003 05:34:28 +0000 (05:34 +0000)
        uuid 82273fdc-e32a-18c3-3f78-827929dc23ea  version 0x0000:0x0000  'eventlog'
        24 calls available
        WARNING: local IDL defines 4 calls

when all the WARNINGs are gone then we know we have all the calls :)
(This used to be commit f5821b2468a0c46d0e5590de59562926d746c349)

source4/Makefile.in
source4/build/pidl/header.pm
source4/build/pidl/parser.pm
source4/librpc/idl/dcerpc.idl
source4/librpc/rpc/dcerpc.h
source4/librpc/rpc/dcerpc_util.c
source4/torture/rpc/mgmt.c
source4/torture/rpc/scanner.c [new file with mode: 0644]
source4/torture/torture.c

index c6b763137eea36d0fbf2777775b28d8ca2e6efe5..e631668e0942372fd7509079348a53a49953997e 100644 (file)
@@ -443,7 +443,8 @@ SMBTORTURE_RAW_OBJ = torture/raw/qfsinfo.o torture/raw/qfileinfo.o torture/raw/s
 SMBTORTURE_RPC_OBJ = torture/rpc/lsa.o torture/rpc/echo.o torture/rpc/dfs.o \
                torture/rpc/spoolss.o torture/rpc/samr.o torture/rpc/wkssvc.o \
                torture/rpc/srvsvc.o torture/rpc/atsvc.o torture/rpc/eventlog.o \
-               torture/rpc/epmapper.o torture/rpc/winreg.o torture/rpc/mgmt.o
+               torture/rpc/epmapper.o torture/rpc/winreg.o torture/rpc/mgmt.o \
+               torture/rpc/scanner.o
 
 SMBTORTURE_OBJ1 = torture/torture.o torture/torture_util.o torture/nbio.o torture/scanner.o \
                torture/utable.o torture/denytest.o torture/mangle_test.o \
index c71b8fbeb10e89dcb147f5cc44f187c33a541606..cdc4522517b0e5869de55fad5de2b0f9a4e780d7 100644 (file)
@@ -241,10 +241,9 @@ sub HeaderInterface($)
            $res .= "#define DCERPC_$name\_UUID \"$if_uuid\"\n";
            $res .= "#define DCERPC_$name\_VERSION $if_version\n";
            $res .= "#define DCERPC_$name\_NAME \"$interface->{NAME}\"\n\n";
+           $res .= "extern const struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n\n";
     }
 
-    $res .= "extern struct dcerpc_interface_table dcerpc_table_$interface->{NAME};\n\n";
-
     foreach my $d (@{$data}) {
            if ($d->{TYPE} eq "FUNCTION") {
                    my $u_name = uc $d->{NAME};
index a7dad3707c84c72205a42c9ceb5a98e389f8ee89..5c80812ec10749e16b3035c665dab9347f7301b6 100644 (file)
@@ -1246,13 +1246,17 @@ sub FunctionTable($)
        my($interface) = shift;
        my($data) = $interface->{DATA};
        my $count = 0;
+       my $uname = uc $interface->{NAME};
 
        foreach my $d (@{$data}) {
                if ($d->{TYPE} eq "FUNCTION") { $count++; }
        }
 
+       if ($count == 0) {
+               return;
+       }
 
-       pidl "static const struct dcerpc_interface_call calls[] = {\n";
+       pidl "static const struct dcerpc_interface_call $interface->{NAME}\_calls[] = {\n";
        foreach my $d (@{$data}) {
                if ($d->{TYPE} eq "FUNCTION") {
                        pidl "\t{\n";
@@ -1266,7 +1270,7 @@ sub FunctionTable($)
        }
        pidl "\t{ NULL, 0, NULL, NULL }\n};\n\n";
 
-       pidl "\nstruct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {\"$interface->{NAME}\", $count,calls};\n\n";
+       pidl "\nconst struct dcerpc_interface_table dcerpc_table_$interface->{NAME} = {\"$interface->{NAME}\", DCERPC_$uname\_UUID, DCERPC_$uname\_VERSION, $count, $interface->{NAME}\_calls};\n\n";
 }
 
 
index d31e734416f65e7cfdd35c0b184c6d66a0d81a8e..b00396e787663958dcc09e7ba49d91187e4f4161 100644 (file)
@@ -78,7 +78,13 @@ interface dcerpc
                [flag(NDR_REMAINING)] DATA_BLOB stub_and_verifier;
        } dcerpc_response;
 
+
+       const int DCERPC_FAULT_OP_RNG_ERROR = 0x1c010002;
+
        typedef struct {
+               uint32 alloc_hint;
+               uint16 context_id;
+               uint8 cancel_count;
                uint32 status;
        } dcerpc_fault;
 
index 9a301db66b5aaccf9d066f7a13c87ce69ebf7400..6f9aa75e8bcd38028fb9c756d70017510984d546 100644 (file)
@@ -78,6 +78,8 @@ struct dcerpc_interface_call {
 
 struct dcerpc_interface_table {
        const char *name;
+       const char *uuid;
+       uint32 if_version;
        uint32 num_calls;
        const struct dcerpc_interface_call *calls;
 };
index fa69425ab09e2ee5a30ad0df24aa0b02b444ee01..e9499f969ba99027f06eab7d43c56ab3b47f4824 100644 (file)
@@ -62,7 +62,8 @@ NTSTATUS dcerpc_epm_map_tcp_port(const char *server,
        GUID guid;
        struct epm_twr_t twr, *twr_r;
 
-       if (strcasecmp(uuid, DCERPC_EPMAPPER_UUID) == 0) {
+       if (strcasecmp(uuid, DCERPC_EPMAPPER_UUID) == 0 ||
+           strcasecmp(uuid, DCERPC_MGMT_UUID) == 0) {
                /* don't lookup epmapper via epmapper! */
                *port = EPMAPPER_PORT;
                return NT_STATUS_OK;
index e3a8146e644a0b0ce624c9d5b0dbb8c2d54b5206..0f3cfffa66afcc7f67d7f7df563d420b9b923271 100644 (file)
@@ -22,6 +22,9 @@
 #include "includes.h"
 
 
+/*
+  ask the server what interface IDs are available on this endpoint
+*/
 static BOOL test_inq_if_ids(struct dcerpc_pipe *p, 
                            TALLOC_CTX *mem_ctx)
 {
@@ -166,11 +169,14 @@ BOOL torture_rpc_mgmt(int dummy)
        TALLOC_CTX *mem_ctx;
        BOOL ret = True;
        int i;
+       char *host = lp_parm_string(-1, "torture", "host");
+       uint32 port;
 
        mem_ctx = talloc_init("torture_rpc_mgmt");
 
-       for (i=0;dcerpc_pipes[i];i++) {
-               
+       for (i=0;dcerpc_pipes[i];i++) {         
+               char *transport = lp_parm_string(-1, "torture", "transport");
+
                /* some interfaces are not mappable */
                if (dcerpc_pipes[i]->num_calls == 0 ||
                    strcmp(dcerpc_pipes[i]->name, "mgmt") == 0) {
@@ -179,6 +185,21 @@ BOOL torture_rpc_mgmt(int dummy)
 
                printf("\nTesting pipe '%s'\n", dcerpc_pipes[i]->name);
 
+               /* on TCP we need to find the right endpoint */
+               if (strcasecmp(transport, "ncacn_ip_tcp") == 0) {
+                       status = dcerpc_epm_map_tcp_port(host, 
+                                                        dcerpc_pipes[i]->uuid, 
+                                                        dcerpc_pipes[i]->if_version, 
+                                                        &port);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               ret = False;
+                               continue;
+                       }
+
+                       lp_set_cmdline("torture:share", 
+                                      talloc_asprintf(mem_ctx, "%u", port));
+               }
+
                status = torture_rpc_connection(&p, 
                                                dcerpc_pipes[i]->name,
                                                DCERPC_MGMT_UUID,
diff --git a/source4/torture/rpc/scanner.c b/source4/torture/rpc/scanner.c
new file mode 100644 (file)
index 0000000..814b28a
--- /dev/null
@@ -0,0 +1,211 @@
+/* 
+   Unix SMB/CIFS implementation.
+
+   scanner for rpc calls
+
+   Copyright (C) Andrew Tridgell 2003
+   
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+/*
+  find the number of calls defined by local IDL
+*/
+static const char *find_idl_name(const char *uuid, uint32 if_version)
+{
+       int i;
+       for (i=0;dcerpc_pipes[i];i++) {
+               if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
+                   dcerpc_pipes[i]->if_version == if_version) {
+                       return dcerpc_pipes[i]->name;
+               }
+       }
+       return "UNKNOWN";
+}
+
+/*
+  find the number of calls defined by local IDL
+*/
+static int num_idl_calls(const char *uuid, uint32 if_version)
+{
+       int i;
+       for (i=0;dcerpc_pipes[i];i++) {
+               if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
+                   dcerpc_pipes[i]->if_version == if_version) {
+                       return dcerpc_pipes[i]->num_calls;
+               }
+       }
+       return -1;
+}
+
+/*
+  work out how many calls there are for an interface
+ */
+static BOOL test_num_calls(const struct dcerpc_interface_table *iface,
+                          TALLOC_CTX *mem_ctx,
+                          struct dcerpc_syntax_id *id)
+{
+       struct dcerpc_pipe *p;
+       NTSTATUS status;
+       const char *uuid;
+       int i;
+       DATA_BLOB stub_in, stub_out;
+       int idl_calls;
+
+       uuid = GUID_string(mem_ctx, &id->uuid);
+
+       status = torture_rpc_connection(&p, iface->name,
+                                       uuid, id->major_version);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("Failed to connect to '%s' on '%s' - %s\n", 
+                      uuid, iface->name, nt_errstr(status));
+               return False;
+       }
+
+       /* make null calls */
+       stub_in = data_blob(NULL, 0);
+
+       status = dcerpc_request(p, 10000, mem_ctx, &stub_in, &stub_out);
+       if (NT_STATUS_IS_OK(status) ||
+           p->last_fault_code != DCERPC_FAULT_OP_RNG_ERROR) {
+               printf("unable to determine call count - %s %08x\n",
+                      nt_errstr(status), p->last_fault_code);
+               goto done;
+       }
+
+       for (i=128;i>=0;i--) {
+               status = dcerpc_request(p, i, mem_ctx, &stub_in, &stub_out);
+               if (NT_STATUS_IS_OK(status) ||
+                   p->last_fault_code != DCERPC_FAULT_OP_RNG_ERROR) break;
+       }
+
+       printf("\t%d calls available\n", i+1);
+       idl_calls = num_idl_calls(uuid, id->major_version);
+       if (idl_calls == -1) {
+               printf("\tinterface not known in local IDL\n");
+       } else if (i+1 != idl_calls) {
+               printf("\tWARNING: local IDL defines %u calls\n", idl_calls);
+       } else {
+               printf("\tOK: matches num_calls in local IDL\n");
+       }
+
+done:
+       torture_rpc_close(p);
+       return True;
+}
+
+/*
+  ask the server what interface IDs are available on this endpoint
+*/
+static BOOL test_inq_if_ids(struct dcerpc_pipe *p, 
+                           TALLOC_CTX *mem_ctx,
+                           const struct dcerpc_interface_table *iface)
+{
+       NTSTATUS status;
+       struct mgmt_inq_if_ids r;
+       int i;
+       
+       status = dcerpc_mgmt_inq_if_ids(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("inq_if_ids failed - %s\n", nt_errstr(status));
+               return False;
+       }
+
+       if (!W_ERROR_IS_OK(r.out.result)) {
+               printf("inq_if_ids gave error code %s\n", win_errstr(r.out.result));
+               return False;
+       }
+
+       if (!r.out.if_id_vector) {
+               printf("inq_if_ids gave NULL if_id_vector\n");
+               return False;
+       }
+
+       for (i=0;i<r.out.if_id_vector->count;i++) {
+               const char *uuid;
+               struct dcerpc_syntax_id *id = r.out.if_id_vector->if_id[i].id;
+               if (!id) continue;
+
+               uuid = GUID_string(mem_ctx, &id->uuid),
+
+               printf("\n\tuuid %s  version 0x%04x:0x%04x  '%s'\n",
+                      uuid,
+                      id->major_version, id->minor_version,
+                      find_idl_name(uuid, id->major_version));
+               test_num_calls(iface, mem_ctx, id);
+       }
+
+       return True;
+}
+
+
+BOOL torture_rpc_scanner(int dummy)
+{
+        NTSTATUS status;
+        struct dcerpc_pipe *p;
+       TALLOC_CTX *mem_ctx;
+       BOOL ret = True;
+       int i;
+       char *host = lp_parm_string(-1, "torture", "host");
+       uint32 port;
+
+       mem_ctx = talloc_init("torture_rpc_scanner");
+
+       for (i=0;dcerpc_pipes[i];i++) {         
+               char *transport = lp_parm_string(-1, "torture", "transport");
+
+               /* some interfaces are not mappable */
+               if (dcerpc_pipes[i]->num_calls == 0 ||
+                   strcmp(dcerpc_pipes[i]->name, "mgmt") == 0) {
+                       continue;
+               }
+
+               printf("\nTesting pipe '%s'\n", dcerpc_pipes[i]->name);
+
+               /* on TCP we need to find the right endpoint */
+               if (strcasecmp(transport, "ncacn_ip_tcp") == 0) {
+                       status = dcerpc_epm_map_tcp_port(host, 
+                                                        dcerpc_pipes[i]->uuid, 
+                                                        dcerpc_pipes[i]->if_version, 
+                                                        &port);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               ret = False;
+                               continue;
+                       }
+
+                       lp_set_cmdline("torture:share", 
+                                      talloc_asprintf(mem_ctx, "%u", port));
+               }
+
+               status = torture_rpc_connection(&p, 
+                                               dcerpc_pipes[i]->name,
+                                               DCERPC_MGMT_UUID,
+                                               DCERPC_MGMT_VERSION);
+               if (!NT_STATUS_IS_OK(status)) {
+                       ret = False;
+                       continue;
+               }
+       
+               if (!test_inq_if_ids(p, mem_ctx, dcerpc_pipes[i])) {
+                       ret = False;
+               }
+
+               torture_rpc_close(p);
+       }
+
+       return ret;
+}
index 7055acbb851617ded21c3a9cdb07862a6c1e802c..9bc494df7fe53f33f5b18797ffb68ee4aab7dc60 100644 (file)
@@ -217,6 +217,10 @@ NTSTATUS torture_rpc_connection(struct dcerpc_pipe **p,
                 return status;
         }
 
+       /* this ensures that the reference count is decremented so
+          a pipe close will really close the link */
+       cli_tree_close(cli->tree);
+
        /* bind to the pipe, using the uuid as the key */
        status = dcerpc_bind_auth_none(*p, pipe_uuid, pipe_version);
        if (!NT_STATUS_IS_OK(status)) {
@@ -4061,6 +4065,7 @@ static struct {
         {"RPC-EPMAPPER", torture_rpc_epmapper, 0},
         {"RPC-WINREG", torture_rpc_winreg, 0},
         {"RPC-MGMT", torture_rpc_mgmt, 0},
+        {"RPC-SCANNER", torture_rpc_scanner, 0},
        {NULL, NULL, 0}};