1/*
2   Unix SMB/CIFS implementation.
3   SMB torture tester - scanning functions
4   Copyright (C) Andrew Tridgell 2001
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#define NO_SYSLOG
22
23#include "includes.h"
24
25#define VERBOSE 0
26#define OP_MIN 0
27#define OP_MAX 20
28
29/****************************************************************************
30look for a partial hit
31****************************************************************************/
32static void trans2_check_hit(const char *format, int op, int level, NTSTATUS status)
33{
34	if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
35	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
36	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
37	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
38	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
39		return;
40	}
41#if VERBOSE
42	printf("possible %s hit op=%3d level=%5d status=%s\n",
43	       format, op, level, nt_errstr(status));
44#endif
45}
46
47/****************************************************************************
48check for existance of a trans2 call
49****************************************************************************/
50static NTSTATUS try_trans2(struct cli_state *cli,
51			 int op,
52			 char *param, char *data,
53			 int param_len, int data_len,
54			 int *rparam_len, int *rdata_len)
55{
56	uint16 setup = op;
57	char *rparam=NULL, *rdata=NULL;
58
59	if (!cli_send_trans(cli, SMBtrans2,
60                            NULL,                           /* name */
61                            -1, 0,                          /* fid, flags */
62                            &setup, 1, 0,                   /* setup, length, max */
63                            param, param_len, 2,            /* param, length, max */
64                            data, data_len, cli->max_xmit   /* data, length, max */
65                           )) {
66		return cli_nt_error(cli);
67	}
68
69	cli_receive_trans(cli, SMBtrans2,
70			   &rparam, rparam_len,
71			   &rdata, rdata_len);
72
73	SAFE_FREE(rdata);
74	SAFE_FREE(rparam);
75
76	return cli_nt_error(cli);
77}
78
79
80static NTSTATUS try_trans2_len(struct cli_state *cli,
81			     const char *format,
82			     int op, int level,
83			     char *param, char *data,
84			     int param_len, int *data_len,
85			     int *rparam_len, int *rdata_len)
86{
87	NTSTATUS ret=NT_STATUS_OK;
88
89	ret = try_trans2(cli, op, param, data, param_len,
90			 sizeof(pstring), rparam_len, rdata_len);
91#if VERBOSE
92	printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
93#endif
94	if (!NT_STATUS_IS_OK(ret)) return ret;
95
96	*data_len = 0;
97	while (*data_len < sizeof(pstring)) {
98		ret = try_trans2(cli, op, param, data, param_len,
99				 *data_len, rparam_len, rdata_len);
100		if (NT_STATUS_IS_OK(ret)) break;
101		*data_len += 2;
102	}
103	if (NT_STATUS_IS_OK(ret)) {
104		printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
105		       format, level, *data_len, *rparam_len, *rdata_len);
106	} else {
107		trans2_check_hit(format, op, level, ret);
108	}
109	return ret;
110}
111
112/****************************************************************************
113check for existance of a trans2 call
114****************************************************************************/
115static BOOL scan_trans2(struct cli_state *cli, int op, int level,
116			int fnum, int dnum, const char *fname)
117{
118	int data_len = 0;
119	int param_len = 0;
120	int rparam_len, rdata_len;
121	pstring param, data;
122	NTSTATUS status;
123
124	memset(data, 0, sizeof(data));
125	data_len = 4;
126
127	/* try with a info level only */
128	param_len = 2;
129	SSVAL(param, 0, level);
130	status = try_trans2_len(cli, "void", op, level, param, data, param_len, &data_len,
131			    &rparam_len, &rdata_len);
132	if (NT_STATUS_IS_OK(status)) return True;
133
134	/* try with a file descriptor */
135	param_len = 6;
136	SSVAL(param, 0, fnum);
137	SSVAL(param, 2, level);
138	SSVAL(param, 4, 0);
139	status = try_trans2_len(cli, "fnum", op, level, param, data, param_len, &data_len,
140				&rparam_len, &rdata_len);
141	if (NT_STATUS_IS_OK(status)) return True;
142
143
144	/* try with a notify style */
145	param_len = 6;
146	SSVAL(param, 0, dnum);
147	SSVAL(param, 2, dnum);
148	SSVAL(param, 4, level);
149	status = try_trans2_len(cli, "notify", op, level, param, data, param_len, &data_len,
150				&rparam_len, &rdata_len);
151	if (NT_STATUS_IS_OK(status)) return True;
152
153	/* try with a file name */
154	param_len = 6;
155	SSVAL(param, 0, level);
156	SSVAL(param, 2, 0);
157	SSVAL(param, 4, 0);
158	param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
159
160	status = try_trans2_len(cli, "fname", op, level, param, data, param_len, &data_len,
161				&rparam_len, &rdata_len);
162	if (NT_STATUS_IS_OK(status)) return True;
163
164	/* try with a new file name */
165	param_len = 6;
166	SSVAL(param, 0, level);
167	SSVAL(param, 2, 0);
168	SSVAL(param, 4, 0);
169	param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
170
171	status = try_trans2_len(cli, "newfile", op, level, param, data, param_len, &data_len,
172				&rparam_len, &rdata_len);
173	cli_unlink(cli, "\\newfile.dat");
174	cli_rmdir(cli, "\\newfile.dat");
175	if (NT_STATUS_IS_OK(status)) return True;
176
177	/* try dfs style  */
178	cli_mkdir(cli, "\\testdir");
179	param_len = 2;
180	SSVAL(param, 0, level);
181	param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
182
183	status = try_trans2_len(cli, "dfs", op, level, param, data, param_len, &data_len,
184				&rparam_len, &rdata_len);
185	cli_rmdir(cli, "\\testdir");
186	if (NT_STATUS_IS_OK(status)) return True;
187
188	return False;
189}
190
191
192BOOL torture_trans2_scan(int dummy)
193{
194	static struct cli_state *cli;
195	int op, level;
196	const char *fname = "\\scanner.dat";
197	int fnum, dnum;
198
199	printf("starting trans2 scan test\n");
200
201	if (!torture_open_connection(&cli)) {
202		return False;
203	}
204
205	fnum = cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC,
206			 DENY_NONE);
207	dnum = cli_open(cli, "\\", O_RDONLY, DENY_NONE);
208
209	for (op=OP_MIN; op<=OP_MAX; op++) {
210		printf("Scanning op=%d\n", op);
211		for (level = 0; level <= 50; level++) {
212			scan_trans2(cli, op, level, fnum, dnum, fname);
213		}
214
215		for (level = 0x100; level <= 0x130; level++) {
216			scan_trans2(cli, op, level, fnum, dnum, fname);
217		}
218
219		for (level = 1000; level < 1050; level++) {
220			scan_trans2(cli, op, level, fnum, dnum, fname);
221		}
222	}
223
224	torture_close_connection(cli);
225
226	printf("trans2 scan finished\n");
227	return True;
228}
229
230
231
232
233/****************************************************************************
234look for a partial hit
235****************************************************************************/
236static void nttrans_check_hit(const char *format, int op, int level, NTSTATUS status)
237{
238	if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_LEVEL) ||
239	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_IMPLEMENTED) ||
240	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED) ||
241	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_UNSUCCESSFUL) ||
242	    NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_INVALID_INFO_CLASS)) {
243		return;
244	}
245#if VERBOSE
246		printf("possible %s hit op=%3d level=%5d status=%s\n",
247		       format, op, level, nt_errstr(status));
248#endif
249}
250
251/****************************************************************************
252check for existance of a nttrans call
253****************************************************************************/
254static NTSTATUS try_nttrans(struct cli_state *cli,
255			 int op,
256			 char *param, char *data,
257			 int param_len, int data_len,
258			 int *rparam_len, int *rdata_len)
259{
260	char *rparam=NULL, *rdata=NULL;
261
262	if (!cli_send_nt_trans(cli, op,
263			       0,
264			       NULL, 0, 0,
265			       param, param_len, 2,            /* param, length, max */
266			       data, data_len, cli->max_xmit   /* data, length, max */
267                           )) {
268		return cli_nt_error(cli);
269	}
270
271	cli_receive_nt_trans(cli,
272			     &rparam, rparam_len,
273			     &rdata, rdata_len);
274
275	SAFE_FREE(rdata);
276	SAFE_FREE(rparam);
277
278	return cli_nt_error(cli);
279}
280
281
282static NTSTATUS try_nttrans_len(struct cli_state *cli,
283			     const char *format,
284			     int op, int level,
285			     char *param, char *data,
286			     int param_len, int *data_len,
287			     int *rparam_len, int *rdata_len)
288{
289	NTSTATUS ret=NT_STATUS_OK;
290
291	ret = try_nttrans(cli, op, param, data, param_len,
292			 sizeof(pstring), rparam_len, rdata_len);
293#if VERBOSE
294	printf("op=%d level=%d ret=%s\n", op, level, nt_errstr(ret));
295#endif
296	if (!NT_STATUS_IS_OK(ret)) return ret;
297
298	*data_len = 0;
299	while (*data_len < sizeof(pstring)) {
300		ret = try_nttrans(cli, op, param, data, param_len,
301				 *data_len, rparam_len, rdata_len);
302		if (NT_STATUS_IS_OK(ret)) break;
303		*data_len += 2;
304	}
305	if (NT_STATUS_IS_OK(ret)) {
306		printf("found %s level=%d data_len=%d rparam_len=%d rdata_len=%d\n",
307		       format, level, *data_len, *rparam_len, *rdata_len);
308	} else {
309		nttrans_check_hit(format, op, level, ret);
310	}
311	return ret;
312}
313
314/****************************************************************************
315check for existance of a nttrans call
316****************************************************************************/
317static BOOL scan_nttrans(struct cli_state *cli, int op, int level,
318			int fnum, int dnum, const char *fname)
319{
320	int data_len = 0;
321	int param_len = 0;
322	int rparam_len, rdata_len;
323	pstring param, data;
324	NTSTATUS status;
325
326	memset(data, 0, sizeof(data));
327	data_len = 4;
328
329	/* try with a info level only */
330	param_len = 2;
331	SSVAL(param, 0, level);
332	status = try_nttrans_len(cli, "void", op, level, param, data, param_len, &data_len,
333			    &rparam_len, &rdata_len);
334	if (NT_STATUS_IS_OK(status)) return True;
335
336	/* try with a file descriptor */
337	param_len = 6;
338	SSVAL(param, 0, fnum);
339	SSVAL(param, 2, level);
340	SSVAL(param, 4, 0);
341	status = try_nttrans_len(cli, "fnum", op, level, param, data, param_len, &data_len,
342				&rparam_len, &rdata_len);
343	if (NT_STATUS_IS_OK(status)) return True;
344
345
346	/* try with a notify style */
347	param_len = 6;
348	SSVAL(param, 0, dnum);
349	SSVAL(param, 2, dnum);
350	SSVAL(param, 4, level);
351	status = try_nttrans_len(cli, "notify", op, level, param, data, param_len, &data_len,
352				&rparam_len, &rdata_len);
353	if (NT_STATUS_IS_OK(status)) return True;
354
355	/* try with a file name */
356	param_len = 6;
357	SSVAL(param, 0, level);
358	SSVAL(param, 2, 0);
359	SSVAL(param, 4, 0);
360	param_len += clistr_push(cli, &param[6], fname, -1, STR_TERMINATE);
361
362	status = try_nttrans_len(cli, "fname", op, level, param, data, param_len, &data_len,
363				&rparam_len, &rdata_len);
364	if (NT_STATUS_IS_OK(status)) return True;
365
366	/* try with a new file name */
367	param_len = 6;
368	SSVAL(param, 0, level);
369	SSVAL(param, 2, 0);
370	SSVAL(param, 4, 0);
371	param_len += clistr_push(cli, &param[6], "\\newfile.dat", -1, STR_TERMINATE);
372
373	status = try_nttrans_len(cli, "newfile", op, level, param, data, param_len, &data_len,
374				&rparam_len, &rdata_len);
375	cli_unlink(cli, "\\newfile.dat");
376	cli_rmdir(cli, "\\newfile.dat");
377	if (NT_STATUS_IS_OK(status)) return True;
378
379	/* try dfs style  */
380	cli_mkdir(cli, "\\testdir");
381	param_len = 2;
382	SSVAL(param, 0, level);
383	param_len += clistr_push(cli, &param[2], "\\testdir", -1, STR_TERMINATE);
384
385	status = try_nttrans_len(cli, "dfs", op, level, param, data, param_len, &data_len,
386				&rparam_len, &rdata_len);
387	cli_rmdir(cli, "\\testdir");
388	if (NT_STATUS_IS_OK(status)) return True;
389
390	return False;
391}
392
393
394BOOL torture_nttrans_scan(int dummy)
395{
396	static struct cli_state *cli;
397	int op, level;
398	const char *fname = "\\scanner.dat";
399	int fnum, dnum;
400
401	printf("starting nttrans scan test\n");
402
403	if (!torture_open_connection(&cli)) {
404		return False;
405	}
406
407	fnum = cli_open(cli, fname, O_RDWR | O_CREAT | O_TRUNC,
408			 DENY_NONE);
409	dnum = cli_open(cli, "\\", O_RDONLY, DENY_NONE);
410
411	for (op=OP_MIN; op<=OP_MAX; op++) {
412		printf("Scanning op=%d\n", op);
413		for (level = 0; level <= 50; level++) {
414			scan_nttrans(cli, op, level, fnum, dnum, fname);
415		}
416
417		for (level = 0x100; level <= 0x130; level++) {
418			scan_nttrans(cli, op, level, fnum, dnum, fname);
419		}
420
421		for (level = 1000; level < 1050; level++) {
422			scan_nttrans(cli, op, level, fnum, dnum, fname);
423		}
424	}
425
426	torture_close_connection(cli);
427
428	printf("nttrans scan finished\n");
429	return True;
430}
431