added an rpc scanner. This prints messages like this:
[samba.git] / source4 / torture / rpc / scanner.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    scanner for rpc calls
5
6    Copyright (C) Andrew Tridgell 2003
7    
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12    
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17    
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 /*
26   find the number of calls defined by local IDL
27 */
28 static const char *find_idl_name(const char *uuid, uint32 if_version)
29 {
30         int i;
31         for (i=0;dcerpc_pipes[i];i++) {
32                 if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
33                     dcerpc_pipes[i]->if_version == if_version) {
34                         return dcerpc_pipes[i]->name;
35                 }
36         }
37         return "UNKNOWN";
38 }
39
40 /*
41   find the number of calls defined by local IDL
42 */
43 static int num_idl_calls(const char *uuid, uint32 if_version)
44 {
45         int i;
46         for (i=0;dcerpc_pipes[i];i++) {
47                 if (strcasecmp(dcerpc_pipes[i]->uuid, uuid) == 0 &&
48                     dcerpc_pipes[i]->if_version == if_version) {
49                         return dcerpc_pipes[i]->num_calls;
50                 }
51         }
52         return -1;
53 }
54
55 /*
56   work out how many calls there are for an interface
57  */
58 static BOOL test_num_calls(const struct dcerpc_interface_table *iface,
59                            TALLOC_CTX *mem_ctx,
60                            struct dcerpc_syntax_id *id)
61 {
62         struct dcerpc_pipe *p;
63         NTSTATUS status;
64         const char *uuid;
65         int i;
66         DATA_BLOB stub_in, stub_out;
67         int idl_calls;
68
69         uuid = GUID_string(mem_ctx, &id->uuid);
70
71         status = torture_rpc_connection(&p, iface->name,
72                                         uuid, id->major_version);
73         if (!NT_STATUS_IS_OK(status)) {
74                 printf("Failed to connect to '%s' on '%s' - %s\n", 
75                        uuid, iface->name, nt_errstr(status));
76                 return False;
77         }
78
79         /* make null calls */
80         stub_in = data_blob(NULL, 0);
81
82         status = dcerpc_request(p, 10000, mem_ctx, &stub_in, &stub_out);
83         if (NT_STATUS_IS_OK(status) ||
84             p->last_fault_code != DCERPC_FAULT_OP_RNG_ERROR) {
85                 printf("unable to determine call count - %s %08x\n",
86                        nt_errstr(status), p->last_fault_code);
87                 goto done;
88         }
89
90         for (i=128;i>=0;i--) {
91                 status = dcerpc_request(p, i, mem_ctx, &stub_in, &stub_out);
92                 if (NT_STATUS_IS_OK(status) ||
93                     p->last_fault_code != DCERPC_FAULT_OP_RNG_ERROR) break;
94         }
95
96         printf("\t%d calls available\n", i+1);
97         idl_calls = num_idl_calls(uuid, id->major_version);
98         if (idl_calls == -1) {
99                 printf("\tinterface not known in local IDL\n");
100         } else if (i+1 != idl_calls) {
101                 printf("\tWARNING: local IDL defines %u calls\n", idl_calls);
102         } else {
103                 printf("\tOK: matches num_calls in local IDL\n");
104         }
105
106 done:
107         torture_rpc_close(p);
108         return True;
109 }
110
111 /*
112   ask the server what interface IDs are available on this endpoint
113 */
114 static BOOL test_inq_if_ids(struct dcerpc_pipe *p, 
115                             TALLOC_CTX *mem_ctx,
116                             const struct dcerpc_interface_table *iface)
117 {
118         NTSTATUS status;
119         struct mgmt_inq_if_ids r;
120         int i;
121         
122         status = dcerpc_mgmt_inq_if_ids(p, mem_ctx, &r);
123         if (!NT_STATUS_IS_OK(status)) {
124                 printf("inq_if_ids failed - %s\n", nt_errstr(status));
125                 return False;
126         }
127
128         if (!W_ERROR_IS_OK(r.out.result)) {
129                 printf("inq_if_ids gave error code %s\n", win_errstr(r.out.result));
130                 return False;
131         }
132
133         if (!r.out.if_id_vector) {
134                 printf("inq_if_ids gave NULL if_id_vector\n");
135                 return False;
136         }
137
138         for (i=0;i<r.out.if_id_vector->count;i++) {
139                 const char *uuid;
140                 struct dcerpc_syntax_id *id = r.out.if_id_vector->if_id[i].id;
141                 if (!id) continue;
142
143                 uuid = GUID_string(mem_ctx, &id->uuid),
144
145                 printf("\n\tuuid %s  version 0x%04x:0x%04x  '%s'\n",
146                        uuid,
147                        id->major_version, id->minor_version,
148                        find_idl_name(uuid, id->major_version));
149                 test_num_calls(iface, mem_ctx, id);
150         }
151
152         return True;
153 }
154
155
156 BOOL torture_rpc_scanner(int dummy)
157 {
158         NTSTATUS status;
159         struct dcerpc_pipe *p;
160         TALLOC_CTX *mem_ctx;
161         BOOL ret = True;
162         int i;
163         char *host = lp_parm_string(-1, "torture", "host");
164         uint32 port;
165
166         mem_ctx = talloc_init("torture_rpc_scanner");
167
168         for (i=0;dcerpc_pipes[i];i++) {         
169                 char *transport = lp_parm_string(-1, "torture", "transport");
170
171                 /* some interfaces are not mappable */
172                 if (dcerpc_pipes[i]->num_calls == 0 ||
173                     strcmp(dcerpc_pipes[i]->name, "mgmt") == 0) {
174                         continue;
175                 }
176
177                 printf("\nTesting pipe '%s'\n", dcerpc_pipes[i]->name);
178
179                 /* on TCP we need to find the right endpoint */
180                 if (strcasecmp(transport, "ncacn_ip_tcp") == 0) {
181                         status = dcerpc_epm_map_tcp_port(host, 
182                                                          dcerpc_pipes[i]->uuid, 
183                                                          dcerpc_pipes[i]->if_version, 
184                                                          &port);
185                         if (!NT_STATUS_IS_OK(status)) {
186                                 ret = False;
187                                 continue;
188                         }
189
190                         lp_set_cmdline("torture:share", 
191                                        talloc_asprintf(mem_ctx, "%u", port));
192                 }
193
194                 status = torture_rpc_connection(&p, 
195                                                 dcerpc_pipes[i]->name,
196                                                 DCERPC_MGMT_UUID,
197                                                 DCERPC_MGMT_VERSION);
198                 if (!NT_STATUS_IS_OK(status)) {
199                         ret = False;
200                         continue;
201                 }
202         
203                 if (!test_inq_if_ids(p, mem_ctx, dcerpc_pipes[i])) {
204                         ret = False;
205                 }
206
207                 torture_rpc_close(p);
208         }
209
210         return ret;
211 }